From 796c54f5f5ded48384938ae790c521407681415d Mon Sep 17 00:00:00 2001 From: teastudiopl Date: Wed, 7 Jan 2026 22:25:37 +0100 Subject: [PATCH 01/67] feat(currency): add configurable currency symbol position Add support for displaying currency symbols before or after the price value, with optional separator between symbol and amount. --- .../plugin-ecommerce/src/currencies/index.ts | 6 +++++ .../src/react/provider/index.tsx | 23 +++++++++++++++---- packages/plugin-ecommerce/src/types/index.ts | 10 ++++++++ .../src/ui/PriceCell/index.tsx | 15 ++++++++---- 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/packages/plugin-ecommerce/src/currencies/index.ts b/packages/plugin-ecommerce/src/currencies/index.ts index 3487a6daa7d..dfd9f9f5c66 100644 --- a/packages/plugin-ecommerce/src/currencies/index.ts +++ b/packages/plugin-ecommerce/src/currencies/index.ts @@ -5,6 +5,8 @@ export const EUR: Currency = { decimals: 2, label: 'Euro', symbol: '€', + symbolPosition: 'before', + symbolSeparator: '', } export const USD: Currency = { @@ -12,6 +14,8 @@ export const USD: Currency = { decimals: 2, label: 'US Dollar', symbol: '$', + symbolPosition: 'before', + symbolSeparator: '', } export const GBP: Currency = { @@ -19,4 +23,6 @@ export const GBP: Currency = { decimals: 2, label: 'British Pound', symbol: '£', + symbolPosition: 'before', + symbolSeparator: '', } diff --git a/packages/plugin-ecommerce/src/react/provider/index.tsx b/packages/plugin-ecommerce/src/react/provider/index.tsx index 311ccf58e91..6b7372ad175 100644 --- a/packages/plugin-ecommerce/src/react/provider/index.tsx +++ b/packages/plugin-ecommerce/src/react/provider/index.tsx @@ -36,6 +36,8 @@ const defaultContext: EcommerceContextType = { decimals: 2, label: 'US Dollar', symbol: '$', + symbolPosition: 'before', + symbolSeparator: '', }, ], }, @@ -44,6 +46,8 @@ const defaultContext: EcommerceContextType = { decimals: 2, label: 'US Dollar', symbol: '$', + symbolPosition: 'before', + symbolSeparator: '', }, decrementItem: async () => {}, incrementItem: async () => {}, @@ -74,6 +78,8 @@ export const EcommerceProvider: React.FC = ({ decimals: 2, label: 'US Dollar', symbol: '$', + symbolPosition: 'before', + symbolSeparator: '', }, ], }, @@ -931,15 +937,22 @@ export const useCurrency = () => { return value.toString() } - if (value === 0) { - return `${currencyToUse.symbol}0.${'0'.repeat(currencyToUse.decimals)}` - } + const { decimals, symbol, symbolPosition = 'before', symbolSeparator = '' } = currencyToUse // Convert from base value (e.g., cents) to decimal value (e.g., dollars) - const decimalValue = value / Math.pow(10, currencyToUse.decimals) + const formattedNumber = + value === 0 + ? `0.${'0'.repeat(decimals)}` + : (value / Math.pow(10, decimals)).toFixed(decimals) + + if (!symbol) { + return formattedNumber + } // Format with the correct number of decimal places - return `${currencyToUse.symbol}${decimalValue.toFixed(currencyToUse.decimals)}` + return symbolPosition === 'before' + ? `${symbol}${symbolSeparator}${formattedNumber}` + : `${formattedNumber}${symbolSeparator}${symbol}` }, [currency], ) diff --git a/packages/plugin-ecommerce/src/types/index.ts b/packages/plugin-ecommerce/src/types/index.ts index 2ffaf38f1df..9e7b99d9043 100644 --- a/packages/plugin-ecommerce/src/types/index.ts +++ b/packages/plugin-ecommerce/src/types/index.ts @@ -246,6 +246,16 @@ export type Currency = { * @example '$' */ symbol: string + /** + * The position of the currency symbol relative to the amount. + * @example 'before' for '$10.00' or 'after' for '10.00€' + */ + symbolPosition: 'after' | 'before' + /** + * The separator between the symbol and the amount. + * @example ' ' (a space) for '€ 10.00' or '' (empty string) for '$10.00' + */ + symbolSeparator?: string } /** diff --git a/packages/plugin-ecommerce/src/ui/PriceCell/index.tsx b/packages/plugin-ecommerce/src/ui/PriceCell/index.tsx index 99e0014b891..5c8421a178b 100644 --- a/packages/plugin-ecommerce/src/ui/PriceCell/index.tsx +++ b/packages/plugin-ecommerce/src/ui/PriceCell/index.tsx @@ -41,9 +41,16 @@ export const PriceCell: React.FC = (args) => { } return ( - - {currency.symbol} - {convertFromBaseValue({ baseValue: cellData, currency })} - +
+ {currency.symbolPosition === 'before' + ? `${currency.symbol}` + : ''} + {currency.symbolPosition === 'before' && currency.symbolSeparator} + {convertFromBaseValue({ baseValue: cellData, currency })} + {currency.symbolPosition === 'after' && currency.symbolSeparator} + {currency.symbolPosition === 'after' + ? `${currency.symbol}` + : ''} +
) } From 0402f5f0a67c6e3bb3a83a8a8fed9b8d65966709 Mon Sep 17 00:00:00 2001 From: Jake Date: Thu, 11 Dec 2025 17:27:30 -0500 Subject: [PATCH 02/67] fix(deps)!: bump minimum next version to 15.4.9 (#14898) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # ⚠️ Security Issue A high-severity Denial of Service ([CVE-2025-55184](https://www.cve.org/CVERecord?id=CVE-2025-55184)) and a medium-severity Source Code Exposure ([CVE-2025-55183](https://www.cve.org/CVERecord?id=CVE-2025-55183)) affect React 19 and frameworks that use it, like Next.js. ## Summary Denial of Service ([CVE-2025-55184](https://www.cve.org/CVERecord?id=CVE-2025-55184)) > A malicious HTTP request can be crafted and sent to any App Router endpoint that, when deserialized, can cause the server process to hang and consume CPU. Source Code Exposure ([CVE-2025-55183](https://www.cve.org/CVERecord?id=CVE-2025-55183)) > A malicious HTTP request can be crafted and sent to any App Router endpoint that can return the compiled source code of Server Actions. This could reveal business logic, but would not expose secrets unless they were hardcoded directly into the Server Action’s code. Full details here: https://vercel.com/kb/bulletin/security-bulletin-cve-2025-55184-and-cve-2025-55183#how-to-upgrade-and-protect-your-next.js-app While this is **not a Payload vulnerability,** it may affect any Payload project running on the affected versions of Next.js. Payload does not install any of these dependencies directly, it simply _enforces_ their versions through its peer dependencies, which will only _warn_ you of the version incompatibilities. You will need to upgrade React and Next.js yourself in your own apps to the patched versions listed below in order to receive these updates. ## Resolution You are strongly encouraged to upgrade your own apps to the nearest patched versions of Next.js and deploy immediately. Quick steps: If using `pnpm` as your package manager, here's a one-liner: ``` pnpm add next@15.4.9 ``` For a full breakdown of the vulnerable packages and their patched releases, see https://vercel.com/kb/bulletin/security-bulletin-cve-2025-55184-and-cve-2025-55183#how-to-upgrade-and-protect-your-next.js-app. Related: https://github.com/payloadcms/payload/pull/14807 --- examples/astro/payload/package.json | 2 +- examples/astro/payload/pnpm-lock.yaml | 6617 +++++++++ examples/auth/package.json | 2 +- examples/auth/pnpm-lock.yaml | 5382 ++++---- examples/custom-components/package.json | 2 +- examples/custom-components/pnpm-lock.yaml | 714 +- examples/custom-server/package.json | 2 +- examples/custom-server/pnpm-lock.yaml | 6436 +++++++++ examples/draft-preview/package.json | 2 +- examples/draft-preview/pnpm-lock.yaml | 668 +- examples/email/package.json | 2 +- examples/email/pnpm-lock.yaml | 763 +- examples/form-builder/package.json | 2 +- examples/form-builder/pnpm-lock.yaml | 849 +- examples/live-preview/package.json | 2 +- examples/live-preview/pnpm-lock.yaml | 659 +- examples/localization/package.json | 2 +- examples/localization/pnpm-lock.yaml | 746 +- examples/multi-tenant/package.json | 2 +- examples/multi-tenant/pnpm-lock.yaml | 678 +- examples/remix/payload/package.json | 2 +- examples/remix/payload/pnpm-lock.yaml | 6610 +++++++++ examples/tailwind-shadcn-ui/package.json | 2 +- examples/tailwind-shadcn-ui/pnpm-lock.yaml | 11289 ++++++---------- examples/whitelabel/package.json | 2 +- examples/whitelabel/pnpm-lock.yaml | 722 +- package.json | 2 +- packages/next/package.json | 2 +- packages/ui/package.json | 2 +- pnpm-lock.yaml | 75 +- templates/_template/package.json | 2 +- templates/blank/package.json | 2 +- templates/ecommerce/package.json | 2 +- templates/plugin/package.json | 2 +- templates/website/package.json | 2 +- templates/with-cloudflare-d1/package.json | 2 +- templates/with-postgres/package.json | 2 +- templates/with-vercel-mongodb/package.json | 2 +- templates/with-vercel-postgres/package.json | 2 +- templates/with-vercel-website/package.json | 2 +- test/package.json | 2 +- .../payload/reference/PLUGIN-DEVELOPMENT.md | 2 +- 42 files changed, 29362 insertions(+), 12902 deletions(-) create mode 100644 examples/astro/payload/pnpm-lock.yaml create mode 100644 examples/custom-server/pnpm-lock.yaml create mode 100644 examples/remix/payload/pnpm-lock.yaml diff --git a/examples/astro/payload/package.json b/examples/astro/payload/package.json index 9d14e74842e..57c94b749a2 100644 --- a/examples/astro/payload/package.json +++ b/examples/astro/payload/package.json @@ -27,7 +27,7 @@ "@payloadcms/richtext-lexical": "3.11.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "15.4.8", + "next": "15.4.9", "payload": "3.11.0", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/examples/astro/payload/pnpm-lock.yaml b/examples/astro/payload/pnpm-lock.yaml new file mode 100644 index 00000000000..4a1f562a6fb --- /dev/null +++ b/examples/astro/payload/pnpm-lock.yaml @@ -0,0 +1,6617 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@payloadcms/db-mongodb': + specifier: 3.11.0 + version: 3.11.0(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)) + '@payloadcms/next': + specifier: 3.11.0 + version: 3.11.0(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + '@payloadcms/richtext-lexical': + specifier: 3.11.0 + version: 3.11.0(0d028be8ae31e9f10c1ea354cfbea024) + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + graphql: + specifier: ^16.8.1 + version: 16.12.0 + next: + specifier: 15.4.9 + version: 15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + payload: + specifier: 3.11.0 + version: 3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + react: + specifier: 19.2.1 + version: 19.2.1 + react-dom: + specifier: 19.2.1 + version: 19.2.1(react@19.2.1) + sharp: + specifier: 0.32.6 + version: 0.32.6 + devDependencies: + '@eslint/eslintrc': + specifier: ^3.2.0 + version: 3.3.3 + '@types/node': + specifier: ^22.5.4 + version: 22.19.2 + '@types/react': + specifier: 19.2.1 + version: 19.2.1 + '@types/react-dom': + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) + eslint: + specifier: ^9.16.0 + version: 9.39.1 + eslint-config-next: + specifier: 15.1.0 + version: 15.1.0(eslint@9.39.1)(typescript@5.7.2) + prettier: + specifier: ^3.4.2 + version: 3.7.4 + typescript: + specifier: 5.7.2 + version: 5.7.2 + +packages: + + '@apidevtools/json-schema-ref-parser@11.9.3': + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} + engines: {node: '>= 16'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@borewit/text-codec@0.1.1': + resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} + + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.0.8': + resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/sortable@7.0.2': + resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} + peerDependencies: + '@dnd-kit/core': ^6.0.7 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + + '@emotion/css@11.13.5': + resolution: {integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + peerDependencies: + react: '>=16.8.0' + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.3': + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.1': + resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@faceless-ui/modal@3.0.0-beta.2': + resolution: {integrity: sha512-UmXvz7Iw3KMO4Pm3llZczU4uc5pPQDb6rdqwoBvYDFgWvkraOAHKx0HxSZgwqQvqOhn8joEFBfFp6/Do2562ow==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + + '@faceless-ui/scroll-info@2.0.0-beta.0': + resolution: {integrity: sha512-pUBhQP8vduA7rVndNsjhaCcds1BykA/Q4iV23JWijU6ZFL/M3Fm9P3ypDS+0VVxolqemNhw8S3FXPwZGgjH4Rw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + + '@faceless-ui/window-info@3.0.0-beta.0': + resolution: {integrity: sha512-Qs8xRA+fl4sU2aFVe9xawxfi5TVZ9VTPuhdQpx9aSv7U5a2F0AXwT61lJfnaJ9Flm8tOcxzq67p8cVZsXNCVeQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.26.28': + resolution: {integrity: sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@lexical/clipboard@0.20.0': + resolution: {integrity: sha512-oHmb9kSVHjeFCd2q8VrEXW22doUHMJ6cGXqo7Ican7Ljl4/9OgRWr+cq55yntoSaJfCrRYkTiZCLDejF2ciSiA==} + + '@lexical/code@0.20.0': + resolution: {integrity: sha512-zFsVGuzIn4CQxEnlW4AG/Hq6cyATVZ4fZTxozE/f5oK4vDPvnY/goRxrzSuAMX73A/HRX3kTEzMDcm4taRM3Mg==} + + '@lexical/devtools-core@0.20.0': + resolution: {integrity: sha512-/CnL+Dfpzw4koy2BTdUICkvrCkMIYG8Y73KB/S1Bt5UzJpD+PV300puWJ0NvUvAj24H78r73jxvK2QUG67Tdaw==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/dragon@0.20.0': + resolution: {integrity: sha512-3DAHF8mSKiPZtXCqu2P8ynSwS3fGXzg4G/V0lXNjBxhmozjzUzWZRWIWtmTlWdEu9GXsoyeM3agcaxyDPJJwkA==} + + '@lexical/hashtag@0.20.0': + resolution: {integrity: sha512-ldOP/d9tA6V9qvLyr3mRYkcYY5ySOHJ2BFOW/jZPxQcj6lWafS8Lk7XdMUpHHDjRpY2Hizsi5MHJkIqFglYXbw==} + + '@lexical/headless@0.20.0': + resolution: {integrity: sha512-PZ9Yxud7UOpVoq3oJ1wb3wb7NHyFt8XLc1IhdNAzTzbZ+L6c9lyomgBFvDs11u/3t9vjtLxGbzkzYKryQE80Ig==} + + '@lexical/history@0.20.0': + resolution: {integrity: sha512-dXtIS31BU6RmLX2KwLAi1EgGl+USeyi+rshh19azACXHPFqONZgPd2t21LOLSFn7C1/W+cSp/kqVDlQVbZUZRA==} + + '@lexical/html@0.20.0': + resolution: {integrity: sha512-ob7QHkEv+mhaZjlurDj90UmEyN9G4rzBPR5QV42PLnu1qMSviMEdI5V3a5/A5aFf/FDDQ+0GAgWBFnA/MEDczQ==} + + '@lexical/link@0.20.0': + resolution: {integrity: sha512-zicDcfgRZPRFZ8WOZv5er0Aqkde+i7QoFVkLQD4dNLLORjoMSJOISJH6VEdjBl3k7QJTxbfrt+xT5d/ZsAN5GA==} + + '@lexical/list@0.20.0': + resolution: {integrity: sha512-ufSse8ui3ooUe0HA/yF/9STrG8wYhIDLMRhELOw80GFCkPJaxs6yRvjfmJooH5IC88rpUJ5XXFFiZKfGxEZLEw==} + + '@lexical/mark@0.20.0': + resolution: {integrity: sha512-1P2izmkgZ4VDp+49rWO1KfWivL5aA30y5kkYbFZ/CS05fgbO7ogMjLSajpz+RN/zzW79v3q4YfikrMgaD23InA==} + + '@lexical/markdown@0.20.0': + resolution: {integrity: sha512-ZoGsECejp9z6MEvc8l81b1h1aWbB3sTq6xOFeUTbDL5vKpA67z5CmQQLi0uZWrygrbO9dSE3Q/JGcodUrczxbw==} + + '@lexical/offset@0.20.0': + resolution: {integrity: sha512-VMhxsxxDGnpVw0jgC8UlDf0Q2RHIHbS49uZgs3l9nP+O+G8s3b76Ta4Tb+iJOK2FY6874/TcQMbSuXGhfpQk8A==} + + '@lexical/overflow@0.20.0': + resolution: {integrity: sha512-z4lElzLm1FVifc7bzBZN4VNKeTuwygpyHQvCJVWXzF2Kbvex43PEYMi8u4A83idVqbmzbyBLASwUJS0voLoPLw==} + + '@lexical/plain-text@0.20.0': + resolution: {integrity: sha512-LvoC+9mm2Im1iO8GgtgaqSfW0T3mIE5GQl1xGxbVNdANmtHmBgRAJn2KfQm1XHZP6zydLRMhZkzC+jfInh2yfQ==} + + '@lexical/react@0.20.0': + resolution: {integrity: sha512-5QbN5AFtZ9efXxU/M01ADhUZgthR0e8WKi5K/w5EPpWtYFDPQnUte3rKUjYJ7uwG1iwcvaCpuMbxJjHQ+i6pDQ==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/rich-text@0.20.0': + resolution: {integrity: sha512-BR1pACdMA+Ymef0f5EN1y+9yP8w7S+9MgmBP1yjr3w4KdqRnfSaGWyxwcHU8eA+zu16QfivpB6501VJ90YeuXw==} + + '@lexical/selection@0.20.0': + resolution: {integrity: sha512-YnkH5UCMNN/em95or/6uwAV31vcENh1Roj+JOg5KD+gJuA7VGdDCy0vZl/o0+1badXozeZ2VRxXNC6JSK7T4+A==} + + '@lexical/table@0.20.0': + resolution: {integrity: sha512-qHuK2rvQUoQDx62YpvJE3Ev4yK9kjRFo79IDBapxrhoXg/wCGQOjMBzVD3G5PWkhyl/GDnww80GwYjLloQLQzg==} + + '@lexical/text@0.20.0': + resolution: {integrity: sha512-Fu64i5CIlEOlgucSdp9XFqB2XqoRsw4at76n93+6RF4+LgGDnu4nLXQVCVxNmLcGyh2WgczuTpnk5P2mHNAIUA==} + + '@lexical/utils@0.20.0': + resolution: {integrity: sha512-sXIa2nowrNxY8VcjjuxZbJ/HovIql8bmInNaxBR03JAYfqMiL5I5/dYgjOQJV49NJnuR1uTY2GwVxVTXCTFUCw==} + + '@lexical/yjs@0.20.0': + resolution: {integrity: sha512-TiHNhu2VkhXN69V+fXVS3xjOQ6aLnheQUGwOAhuFkDPL3VLCb0yl2Mgydpayn+3Grwii4ZBHcF7oCC84GiU5bw==} + peerDependencies: + yjs: '>=13.5.22' + + '@monaco-editor/loader@1.7.0': + resolution: {integrity: sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==} + + '@monaco-editor/react@4.6.0': + resolution: {integrity: sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==} + peerDependencies: + monaco-editor: '>= 0.25.0 < 1' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + + '@mongodb-js/saslprep@1.4.0': + resolution: {integrity: sha512-ZHzx7Z3rdlWL1mECydvpryWN/ETXJiCxdgQKTAH+djzIPe77HdnSizKBDi1TVDXZjXyOj2IqEG/vPw71ULF06w==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@next/env@15.4.9': + resolution: {integrity: sha512-OYR0RulK5phnbxxzcLE4/ECgfx1PL3EHrDbjyelJ7jauaO+/Qvj5gG8JPMltB51CygC2KrZ0aAfYLjPYjYY17A==} + + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + + '@next/eslint-plugin-next@15.1.0': + resolution: {integrity: sha512-+jPT0h+nelBT6HC9ZCHGc7DgGVy04cv4shYdAe6tKlEbjQUtwU3LzQhzbDHQyY2m6g39m6B0kOFVuLGBrxxbGg==} + + '@next/swc-darwin-arm64@15.4.8': + resolution: {integrity: sha512-Pf6zXp7yyQEn7sqMxur6+kYcywx5up1J849psyET7/8pG2gQTVMjU3NzgIt8SeEP5to3If/SaWmaA6H6ysBr1A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.4.8': + resolution: {integrity: sha512-xla6AOfz68a6kq3gRQccWEvFC/VRGJmA/QuSLENSO7CZX5WIEkSz7r1FdXUjtGCQ1c2M+ndUAH7opdfLK1PQbw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.4.8': + resolution: {integrity: sha512-y3fmp+1Px/SJD+5ntve5QLZnGLycsxsVPkTzAc3zUiXYSOlTPqT8ynfmt6tt4fSo1tAhDPmryXpYKEAcoAPDJw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@15.4.8': + resolution: {integrity: sha512-DX/L8VHzrr1CfwaVjBQr3GWCqNNFgyWJbeQ10Lx/phzbQo3JNAxUok1DZ8JHRGcL6PgMRgj6HylnLNndxn4Z6A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@15.4.8': + resolution: {integrity: sha512-9fLAAXKAL3xEIFdKdzG5rUSvSiZTLLTCc6JKq1z04DR4zY7DbAPcRvNm3K1inVhTiQCs19ZRAgUerHiVKMZZIA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@15.4.8': + resolution: {integrity: sha512-s45V7nfb5g7dbS7JK6XZDcapicVrMMvX2uYgOHP16QuKH/JA285oy6HcxlKqwUNaFY/UC6EvQ8QZUOo19cBKSA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@15.4.8': + resolution: {integrity: sha512-KjgeQyOAq7t/HzAJcWPGA8X+4WY03uSCZ2Ekk98S9OgCFsb6lfBE3dbUzUuEQAN2THbwYgFfxX2yFTCMm8Kehw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.4.8': + resolution: {integrity: sha512-Exsmf/+42fWVnLMaZHzshukTBxZrSwuuLKFvqhGHJ+mC1AokqieLY/XzAl3jc/CqhXLqLY3RRjkKJ9YnLPcRWg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@payloadcms/db-mongodb@3.11.0': + resolution: {integrity: sha512-mPtbgo/e1HJe2kHtIe+xKUne0jswg5t/OxlLZ1h22S4FII7m/dK3ezpC+EHI4Z4lHSbKt0yIPGrKANxmmkkOsQ==} + peerDependencies: + payload: 3.11.0 + + '@payloadcms/graphql@3.11.0': + resolution: {integrity: sha512-IYiivNdm++wiUvHa40S9rM/rjwrh7D/7rofZjR7aDEvWiYj2lF/ZfmG7PY22S7ZCYcmq4+bgOqSk4JYz5lXynw==} + hasBin: true + peerDependencies: + graphql: ^16.8.1 + payload: 3.11.0 + + '@payloadcms/next@3.11.0': + resolution: {integrity: sha512-Ut1Mrfv5pXKza1kipv5C80KZ/fyziaNsAV73gCOykritPsownRyeXugaEobcL8GcifvAoduk75mAXAw+rwizgw==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + graphql: ^16.8.1 + next: ^15.0.0 + payload: 3.11.0 + + '@payloadcms/richtext-lexical@3.11.0': + resolution: {integrity: sha512-ONR+sSRayllhTEk1N9b1jXzmKUzUKU73/KmtQNu90+mmvs6rdqNbDcjerlE/uVprkvDO/gRpI+jVFNlFD/cuBw==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + '@faceless-ui/modal': 3.0.0-beta.2 + '@faceless-ui/scroll-info': 2.0.0-beta.0 + '@lexical/headless': 0.20.0 + '@lexical/html': 0.20.0 + '@lexical/link': 0.20.0 + '@lexical/list': 0.20.0 + '@lexical/mark': 0.20.0 + '@lexical/react': 0.20.0 + '@lexical/rich-text': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/table': 0.20.0 + '@lexical/utils': 0.20.0 + '@payloadcms/next': 3.11.0 + lexical: 0.20.0 + payload: 3.11.0 + react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + + '@payloadcms/translations@3.11.0': + resolution: {integrity: sha512-6iGYqe3lE5ARBcMDbXOcPB0mMK2oxyn46fI2c06u2VEGS6z4b8B4cDoNfHv6ZhInzTS94ZtZUnbK1heR8KcEcg==} + + '@payloadcms/ui@3.11.0': + resolution: {integrity: sha512-iB8BThtP+gFnt/DA1NHTdTTv5TZx3aYWQca/VGhrYU5SCR1SUVGcBpO7qW2eQiHWjnaMKA8tvqeY8T5mkEdfRA==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + next: ^15.0.0 + payload: 3.11.0 + react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@rushstack/eslint-patch@1.15.0': + resolution: {integrity: sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/acorn@4.0.6': + resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} + + '@types/busboy@1.5.4': + resolution: {integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/lodash@4.17.21': + resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@22.19.2': + resolution: {integrity: sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==} + + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react-transition-group@4.4.12': + resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} + peerDependencies: + '@types/react': '*' + + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@11.0.5': + resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} + + '@typescript-eslint/eslint-plugin@8.49.0': + resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.49.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.49.0': + resolution: {integrity: sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.49.0': + resolution: {integrity: sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.49.0': + resolution: {integrity: sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.49.0': + resolution: {integrity: sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.49.0': + resolution: {integrity: sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.49.0': + resolution: {integrity: sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.49.0': + resolution: {integrity: sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.49.0': + resolution: {integrity: sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.49.0': + resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.11.0: + resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + b4a@1.7.3: + resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + bare-fs@4.5.2: + resolution: {integrity: sha512-veTnRzkb6aPHOvSKIOy60KzURfBdUflr5VReI+NSaPL6xf+XLdONQgZgpYvUuZLVQ8dCqxpBAudaOM1+KpAUxw==} + engines: {bare: '>=1.16.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-os@3.6.2: + resolution: {integrity: sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==} + engines: {bare: '>=1.14.0'} + + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.7.0: + resolution: {integrity: sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==} + peerDependencies: + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.3.2: + resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + body-scroll-lock@4.0.0-beta.0: + resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + bson-objectid@2.0.4: + resolution: {integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==} + + bson@6.10.4: + resolution: {integrity: sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==} + engines: {node: '>=16.20.1'} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001760: + resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + charenc@0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + console-table-printer@2.12.1: + resolution: {integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==} + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + croner@9.0.0: + resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==} + engines: {node: '>=18.0'} + + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crypt@0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + + cssfilter@0.0.10: + resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + dataloader@2.2.3: + resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==} + + date-fns@3.6.0: + resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-next@15.1.0: + resolution: {integrity: sha512-gADO+nKVseGso3DtOrYX9H7TxB/MuX7AUYhMlvQMqLYvUWu4HrOQuU7cC1HW74tHIqkAvXdwgAz3TCbczzSEXw==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.39.1: + resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + fast-copy@3.0.2: + resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + file-type@19.3.0: + resolution: {integrity: sha512-mROwiKLZf/Kwa/2Rol+OOZQn1eyTkPB3ZTwC0ExY6OLFCbgxHYZvBm7xI77NvfZFMKBsmuXfmLJnD4eEftEhrA==} + engines: {node: '>=18'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + focus-trap@7.5.4: + resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graphql-http@1.22.4: + resolution: {integrity: sha512-OC3ucK988teMf+Ak/O+ZJ0N2ukcgrEurypp8ePyJFWq83VzwRAmHxxr+XxrMpxO/FIwI4a7m/Fzv3tWGJv0wPA==} + engines: {node: '>=12'} + peerDependencies: + graphql: '>=0.11 <=16' + + graphql-playground-html@1.6.30: + resolution: {integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==} + + graphql-scalars@1.22.2: + resolution: {integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==} + engines: {node: '>=10'} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + + graphql@16.12.0: + resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + + http-status@1.6.2: + resolution: {integrity: sha512-oUExvfNckrpTpDazph7kNG8sQi5au3BeTo0idaZFXEhTaJKu7GNJCLHI0rYY2wljm548MSTM+Ljj/c6anqu2zQ==} + engines: {node: '>= 0.4.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + image-size@1.2.1: + resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} + engines: {node: '>=16.x'} + hasBin: true + + immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-arrayish@0.3.4: + resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jose@5.9.6: + resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-to-typescript@15.0.3: + resolution: {integrity: sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==} + engines: {node: '>=16.0.0'} + hasBin: true + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + kareem@2.6.3: + resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==} + engines: {node: '>=12.0.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lexical@0.20.0: + resolution: {integrity: sha512-lJEHLFACXqRf3u/VlIOu9T7MJ51O4la92uOBwiS9Sx+juDK3Nrru5Vgl1aUirV1qK8XEM3h6Org2HcrsrzZ3ZA==} + + lib0@0.2.114: + resolution: {integrity: sha512-gcxmNFzA4hv8UYi8j43uPlQ7CGcyMJ2KQb5kZASw6SnAKAf10hK12i2fjrS3Cl/ugZa5Ui6WwIu1/6MIXiHttQ==} + engines: {node: '>=16'} + hasBin: true + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + marked@14.0.0: + resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} + engines: {node: '>= 18'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + md5@2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-mdx-jsx@3.1.3: + resolution: {integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + memoize-one@6.0.0: + resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-mdx-jsx@3.0.1: + resolution: {integrity: sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + monaco-editor@0.55.1: + resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + + mongodb-connection-string-url@3.0.2: + resolution: {integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==} + + mongodb@6.10.0: + resolution: {integrity: sha512-gP9vduuYWb9ZkDM546M+MP2qKVk5ZG2wPF63OvSRuUbqCR+11ZCAE1mOfllhlAG0wcoJY5yDL/rV3OmYEwXIzg==} + engines: {node: '>=16.20.1'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.188.0 + '@mongodb-js/zstd': ^1.1.0 + gcp-metadata: ^5.2.0 + kerberos: ^2.0.1 + mongodb-client-encryption: '>=6.0.0 <7' + snappy: ^7.2.2 + socks: ^2.7.1 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + + mongoose-aggregate-paginate-v2@1.1.2: + resolution: {integrity: sha512-Ai478tHedZy3U2ITBEp2H4rQEviRan3TK4p/umlFqIzgPF1R0hNKvzzQGIb1l2h+Z32QLU3NqaoWKu4vOOUElQ==} + engines: {node: '>=4.0.0'} + + mongoose-paginate-v2@1.8.5: + resolution: {integrity: sha512-kFxhot+yw9KmpAGSSrF/o+f00aC2uawgNUbhyaM0USS9L7dln1NA77/pLg4lgOaRgXMtfgCENamjqZwIM1Zrig==} + engines: {node: '>=4.0.0'} + + mongoose@8.8.3: + resolution: {integrity: sha512-/I4n/DcXqXyIiLRfAmUIiTjj3vXfeISke8dt4U4Y8Wfm074Wa6sXnQrXN49NFOFf2mM1kUdOXryoBvkuCnr+Qw==} + engines: {node: '>=16.20.1'} + + mpath@0.9.0: + resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} + engines: {node: '>=4.0.0'} + + mquery@5.0.0: + resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==} + engines: {node: '>=14.0.0'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + next@15.4.9: + resolution: {integrity: sha512-/NedNmbiH4Umt/7SohT9VKxEdBt02Lj33xHrukE7d8Li6juT+75sEq4a4U06jggrvdbklKgr78OZEyWZ8XRrtw==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-abi@3.85.0: + resolution: {integrity: sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==} + engines: {node: '>=10'} + + node-addon-api@6.1.0: + resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object-to-formdata@4.5.1: + resolution: {integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + payload@3.11.0: + resolution: {integrity: sha512-OdPS95bn5JxurxBZK5HzQiED4T1nR6MZbX8zQSppTHBPL7chsujLl7U9BGMgY1njA26rOoy/mjZc2v4phhWAtw==} + engines: {node: ^18.20.2 || >=20.9.0} + hasBin: true + peerDependencies: + graphql: ^16.8.1 + + peek-readable@5.4.2: + resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} + engines: {node: '>=14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-pretty@13.0.0: + resolution: {integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==} + hasBin: true + + pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + + pino@9.5.0: + resolution: {integrity: sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==} + hasBin: true + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + engines: {node: '>=14'} + hasBin: true + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + process-warning@4.0.1: + resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs-esm@7.0.2: + resolution: {integrity: sha512-D8NAthKSD7SGn748v+GLaaO6k08Mvpoqroa35PqIQC4gtUa8/Pb/k+r0m0NnGBVbHDP1gKZ2nVywqfMisRhV5A==} + engines: {node: '>=18'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-datepicker@7.5.0: + resolution: {integrity: sha512-6MzeamV8cWSOcduwePHfGqY40acuGlS1cG//ePHT6bVbLxWyqngaStenfH03n1wbzOibFggF66kWaBTb1SbTtQ==} + peerDependencies: + react: ^16.9.0 || ^17 || ^18 + react-dom: ^16.9.0 || ^17 || ^18 + + react-diff-viewer-continued@3.2.6: + resolution: {integrity: sha512-GrzyqQnjIMoej+jMjWvtVSsQqhXgzEGqpXlJ2dAGfOk7Q26qcm8Gu6xtI430PBUyZsERe8BJSQf+7VZZo8IBNQ==} + engines: {node: '>= 8'} + peerDependencies: + react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + + react-dom@19.2.1: + resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==} + peerDependencies: + react: ^19.2.1 + + react-error-boundary@3.1.4: + resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} + engines: {node: '>=10', npm: '>=6'} + peerDependencies: + react: '>=16.13.1' + + react-error-boundary@4.1.2: + resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} + peerDependencies: + react: '>=16.13.1' + + react-image-crop@10.1.8: + resolution: {integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==} + peerDependencies: + react: '>=16.13.1' + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-select@5.9.0: + resolution: {integrity: sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + + react@19.2.1: + resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==} + engines: {node: '>=0.10.0'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + sanitize-filename@1.6.3: + resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + + sass@1.77.4: + resolution: {integrity: sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==} + engines: {node: '>=14.0.0'} + hasBin: true + + scheduler@0.25.0: + resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + scmp@2.1.0: + resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} + + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + sharp@0.32.6: + resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} + engines: {node: '>=14.15.0'} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + sift@17.1.3: + resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + simple-swizzle@0.2.4: + resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} + + simple-wcswidth@1.1.2: + resolution: {integrity: sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + sonic-boom@4.2.0: + resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + + sonner@1.7.4: + resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + streamx@2.23.0: + resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strtok3@8.1.0: + resolution: {integrity: sha512-ExzDvHYPj6F6QkSNe/JxSlBxTh3OrI6wrAIz53ulxo1c4hBJ1bT9C/JrAthEKHWG9riVH3Xzg7B03Oxty6S2Lw==} + engines: {node: '>=16'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-fs@3.1.1: + resolution: {integrity: sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + token-types@6.1.1: + resolution: {integrity: sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ==} + engines: {node: '>=14.16'} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + truncate-utf8-bytes@1.0.2: + resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-essentials@10.0.3: + resolution: {integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==} + peerDependencies: + typescript: '>=4.5.0' + peerDependenciesMeta: + typescript: + optional: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.19.2: + resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} + engines: {node: '>=18.0.0'} + hasBin: true + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-context-selector@2.0.0: + resolution: {integrity: sha512-owfuSmUNd3eNp3J9CdDl0kMgfidV+MkDvHPpvthN5ThqM+ibMccNE0k+Iq7TWC6JPFvGZqanqiGCuQx6DyV24g==} + peerDependencies: + react: '>=18.0.0' + scheduler: '>=0.19.0' + + use-isomorphic-layout-effect@1.2.1: + resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + utf8-byte-length@1.0.5: + resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xss@1.0.15: + resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==} + engines: {node: '>= 0.10.0'} + hasBin: true + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yjs@13.6.27: + resolution: {integrity: sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@apidevtools/json-schema-ref-parser@11.9.3': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@borewit/text-codec@0.1.1': {} + + '@dnd-kit/accessibility@3.1.1(react@19.2.1)': + dependencies: + react: 19.2.1 + tslib: 2.8.1 + + '@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@dnd-kit/accessibility': 3.1.1(react@19.2.1) + '@dnd-kit/utilities': 3.2.2(react@19.2.1) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + tslib: 2.8.1 + + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/utilities': 3.2.2(react@19.2.1) + react: 19.2.1 + tslib: 2.8.1 + + '@dnd-kit/utilities@3.2.2(react@19.2.1)': + dependencies: + react: 19.2.1 + tslib: 2.8.1 + + '@emnapi/core@1.7.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.27.1 + '@babel/runtime': 7.28.4 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/css@11.13.5': + dependencies: + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + transitivePeerDependencies: + - supports-color + + '@emotion/hash@0.9.2': {} + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.1)': + dependencies: + '@babel/runtime': 7.28.4 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.1) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.1 + optionalDependencies: + '@types/react': 19.2.1 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.2.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.1)': + dependencies: + react: 19.2.1 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + + '@esbuild/aix-ppc64@0.23.1': + optional: true + + '@esbuild/android-arm64@0.23.1': + optional: true + + '@esbuild/android-arm@0.23.1': + optional: true + + '@esbuild/android-x64@0.23.1': + optional: true + + '@esbuild/darwin-arm64@0.23.1': + optional: true + + '@esbuild/darwin-x64@0.23.1': + optional: true + + '@esbuild/freebsd-arm64@0.23.1': + optional: true + + '@esbuild/freebsd-x64@0.23.1': + optional: true + + '@esbuild/linux-arm64@0.23.1': + optional: true + + '@esbuild/linux-arm@0.23.1': + optional: true + + '@esbuild/linux-ia32@0.23.1': + optional: true + + '@esbuild/linux-loong64@0.23.1': + optional: true + + '@esbuild/linux-mips64el@0.23.1': + optional: true + + '@esbuild/linux-ppc64@0.23.1': + optional: true + + '@esbuild/linux-riscv64@0.23.1': + optional: true + + '@esbuild/linux-s390x@0.23.1': + optional: true + + '@esbuild/linux-x64@0.23.1': + optional: true + + '@esbuild/netbsd-x64@0.23.1': + optional: true + + '@esbuild/openbsd-arm64@0.23.1': + optional: true + + '@esbuild/openbsd-x64@0.23.1': + optional: true + + '@esbuild/sunos-x64@0.23.1': + optional: true + + '@esbuild/win32-arm64@0.23.1': + optional: true + + '@esbuild/win32-ia32@0.23.1': + optional: true + + '@esbuild/win32-x64@0.23.1': + optional: true + + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)': + dependencies: + eslint: 9.39.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.3': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.1': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + body-scroll-lock: 4.0.0-beta.0 + focus-trap: 7.5.4 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + + '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@floating-ui/react@0.26.28(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@floating-ui/utils': 0.2.10 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + tabbable: 6.3.0 + + '@floating-ui/utils@0.2.10': {} + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.7.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jsdevtools/ono@7.1.3': {} + + '@lexical/clipboard@0.20.0': + dependencies: + '@lexical/html': 0.20.0 + '@lexical/list': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/code@0.20.0': + dependencies: + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + prismjs: 1.30.0 + + '@lexical/devtools-core@0.20.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@lexical/html': 0.20.0 + '@lexical/link': 0.20.0 + '@lexical/mark': 0.20.0 + '@lexical/table': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@lexical/dragon@0.20.0': + dependencies: + lexical: 0.20.0 + + '@lexical/hashtag@0.20.0': + dependencies: + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/headless@0.20.0': + dependencies: + lexical: 0.20.0 + + '@lexical/history@0.20.0': + dependencies: + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/html@0.20.0': + dependencies: + '@lexical/selection': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/link@0.20.0': + dependencies: + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/list@0.20.0': + dependencies: + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/mark@0.20.0': + dependencies: + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/markdown@0.20.0': + dependencies: + '@lexical/code': 0.20.0 + '@lexical/link': 0.20.0 + '@lexical/list': 0.20.0 + '@lexical/rich-text': 0.20.0 + '@lexical/text': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/offset@0.20.0': + dependencies: + lexical: 0.20.0 + + '@lexical/overflow@0.20.0': + dependencies: + lexical: 0.20.0 + + '@lexical/plain-text@0.20.0': + dependencies: + '@lexical/clipboard': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/react@0.20.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(yjs@13.6.27)': + dependencies: + '@lexical/clipboard': 0.20.0 + '@lexical/code': 0.20.0 + '@lexical/devtools-core': 0.20.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@lexical/dragon': 0.20.0 + '@lexical/hashtag': 0.20.0 + '@lexical/history': 0.20.0 + '@lexical/link': 0.20.0 + '@lexical/list': 0.20.0 + '@lexical/mark': 0.20.0 + '@lexical/markdown': 0.20.0 + '@lexical/overflow': 0.20.0 + '@lexical/plain-text': 0.20.0 + '@lexical/rich-text': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/table': 0.20.0 + '@lexical/text': 0.20.0 + '@lexical/utils': 0.20.0 + '@lexical/yjs': 0.20.0(yjs@13.6.27) + lexical: 0.20.0 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-error-boundary: 3.1.4(react@19.2.1) + transitivePeerDependencies: + - yjs + + '@lexical/rich-text@0.20.0': + dependencies: + '@lexical/clipboard': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/selection@0.20.0': + dependencies: + lexical: 0.20.0 + + '@lexical/table@0.20.0': + dependencies: + '@lexical/clipboard': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/text@0.20.0': + dependencies: + lexical: 0.20.0 + + '@lexical/utils@0.20.0': + dependencies: + '@lexical/list': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/table': 0.20.0 + lexical: 0.20.0 + + '@lexical/yjs@0.20.0(yjs@13.6.27)': + dependencies: + '@lexical/offset': 0.20.0 + '@lexical/selection': 0.20.0 + lexical: 0.20.0 + yjs: 13.6.27 + + '@monaco-editor/loader@1.7.0': + dependencies: + state-local: 1.0.7 + + '@monaco-editor/react@4.6.0(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + dependencies: + '@monaco-editor/loader': 1.7.0 + monaco-editor: 0.55.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + '@mongodb-js/saslprep@1.4.0': + dependencies: + sparse-bitfield: 3.0.3 + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@next/env@15.4.9': {} + + '@next/env@15.5.8': {} + + '@next/eslint-plugin-next@15.1.0': + dependencies: + fast-glob: 3.3.1 + + '@next/swc-darwin-arm64@15.4.8': + optional: true + + '@next/swc-darwin-x64@15.4.8': + optional: true + + '@next/swc-linux-arm64-gnu@15.4.8': + optional: true + + '@next/swc-linux-arm64-musl@15.4.8': + optional: true + + '@next/swc-linux-x64-gnu@15.4.8': + optional: true + + '@next/swc-linux-x64-musl@15.4.8': + optional: true + + '@next/swc-win32-arm64-msvc@15.4.8': + optional: true + + '@next/swc-win32-x64-msvc@15.4.8': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@payloadcms/db-mongodb@3.11.0(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))': + dependencies: + http-status: 1.6.2 + mongoose: 8.8.3 + mongoose-aggregate-paginate-v2: 1.1.2 + mongoose-paginate-v2: 1.8.5 + payload: 3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + prompts: 2.4.2 + uuid: 10.0.0 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + - supports-color + + '@payloadcms/graphql@3.11.0(graphql@16.12.0)(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(typescript@5.7.2)': + dependencies: + graphql: 16.12.0 + graphql-scalars: 1.22.2(graphql@16.12.0) + payload: 3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + pluralize: 8.0.0 + ts-essentials: 10.0.3(typescript@5.7.2) + tsx: 4.19.2 + transitivePeerDependencies: + - typescript + + '@payloadcms/next@3.11.0(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@payloadcms/graphql': 3.11.0(graphql@16.12.0)(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(typescript@5.7.2) + '@payloadcms/translations': 3.11.0 + '@payloadcms/ui': 3.11.0(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + busboy: 1.6.0 + file-type: 19.3.0 + graphql: 16.12.0 + graphql-http: 1.22.4(graphql@16.12.0) + graphql-playground-html: 1.6.30 + http-status: 1.6.2 + next: 15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + path-to-regexp: 6.3.0 + payload: 3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + qs-esm: 7.0.2 + react-diff-viewer-continued: 3.2.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + sass: 1.77.4 + sonner: 1.7.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + uuid: 10.0.0 + transitivePeerDependencies: + - '@types/react' + - monaco-editor + - react + - react-dom + - supports-color + - typescript + + '@payloadcms/richtext-lexical@3.11.0(0d028be8ae31e9f10c1ea354cfbea024)': + dependencies: + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@lexical/headless': 0.20.0 + '@lexical/html': 0.20.0 + '@lexical/link': 0.20.0 + '@lexical/list': 0.20.0 + '@lexical/mark': 0.20.0 + '@lexical/react': 0.20.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(yjs@13.6.27) + '@lexical/rich-text': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/table': 0.20.0 + '@lexical/utils': 0.20.0 + '@payloadcms/next': 3.11.0(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + '@payloadcms/translations': 3.11.0 + '@payloadcms/ui': 3.11.0(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + '@types/uuid': 10.0.0 + acorn: 8.12.1 + bson-objectid: 2.0.4 + dequal: 2.0.3 + escape-html: 1.0.3 + lexical: 0.20.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-mdx-jsx: 3.1.3 + micromark-extension-mdx-jsx: 3.0.1 + payload: 3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-error-boundary: 4.1.2(react@19.2.1) + ts-essentials: 10.0.3(typescript@5.7.2) + uuid: 10.0.0 + transitivePeerDependencies: + - '@types/react' + - monaco-editor + - next + - supports-color + - typescript + + '@payloadcms/translations@3.11.0': + dependencies: + date-fns: 4.1.0 + + '@payloadcms/ui@3.11.0(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@monaco-editor/react': 4.6.0(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@payloadcms/translations': 3.11.0 + body-scroll-lock: 4.0.0-beta.0 + bson-objectid: 2.0.4 + date-fns: 4.1.0 + dequal: 2.0.3 + md5: 2.3.0 + next: 15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + object-to-formdata: 4.5.1 + payload: 3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + qs-esm: 7.0.2 + react: 19.2.1 + react-datepicker: 7.5.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react-dom: 19.2.1(react@19.2.1) + react-image-crop: 10.1.8(react@19.2.1) + react-select: 5.9.0(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + scheduler: 0.25.0 + sonner: 1.7.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + ts-essentials: 10.0.3(typescript@5.7.2) + use-context-selector: 2.0.0(react@19.2.1)(scheduler@0.25.0) + uuid: 10.0.0 + transitivePeerDependencies: + - '@types/react' + - monaco-editor + - supports-color + - typescript + + '@rtsao/scc@1.1.0': {} + + '@rushstack/eslint-patch@1.15.0': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tokenizer/token@0.3.0': {} + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/acorn@4.0.6': + dependencies: + '@types/estree': 1.0.8 + + '@types/busboy@1.5.4': + dependencies: + '@types/node': 22.19.2 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + + '@types/estree@1.0.8': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/lodash@4.17.21': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@22.19.2': + dependencies: + undici-types: 6.21.0 + + '@types/parse-json@4.0.2': {} + + '@types/react-dom@19.2.1(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 + + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 + + '@types/react@19.2.1': + dependencies: + csstype: 3.2.3 + + '@types/trusted-types@2.0.7': + optional: true + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@types/uuid@10.0.0': {} + + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@11.0.5': + dependencies: + '@types/webidl-conversions': 7.0.3 + + '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.2))(eslint@9.39.1)(typescript@5.7.2)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.7.2) + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/type-utils': 8.49.0(eslint@9.39.1)(typescript@5.7.2) + '@typescript-eslint/utils': 8.49.0(eslint@9.39.1)(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.49.0 + eslint: 9.39.1 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.2)': + dependencies: + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.7.2) + '@typescript-eslint/visitor-keys': 8.49.0 + debug: 4.4.3 + eslint: 9.39.1 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.49.0(typescript@5.7.2)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.7.2) + '@typescript-eslint/types': 8.49.0 + debug: 4.4.3 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.49.0': + dependencies: + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/visitor-keys': 8.49.0 + + '@typescript-eslint/tsconfig-utils@8.49.0(typescript@5.7.2)': + dependencies: + typescript: 5.7.2 + + '@typescript-eslint/type-utils@8.49.0(eslint@9.39.1)(typescript@5.7.2)': + dependencies: + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.7.2) + '@typescript-eslint/utils': 8.49.0(eslint@9.39.1)(typescript@5.7.2) + debug: 4.4.3 + eslint: 9.39.1 + ts-api-utils: 2.1.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.49.0': {} + + '@typescript-eslint/typescript-estree@8.49.0(typescript@5.7.2)': + dependencies: + '@typescript-eslint/project-service': 8.49.0(typescript@5.7.2) + '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.7.2) + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/visitor-keys': 8.49.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.7.2) + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.49.0(eslint@9.39.1)(typescript@5.7.2)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.7.2) + eslint: 9.39.1 + typescript: 5.7.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.49.0': + dependencies: + '@typescript-eslint/types': 8.49.0 + eslint-visitor-keys: 4.2.1 + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.12.1: {} + + acorn@8.15.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + atomic-sleep@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.11.0: {} + + axobject-query@4.1.0: {} + + b4a@1.7.3: {} + + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.28.4 + cosmiconfig: 7.1.0 + resolve: 1.22.11 + + balanced-match@1.0.2: {} + + bare-events@2.8.2: {} + + bare-fs@4.5.2: + dependencies: + bare-events: 2.8.2 + bare-path: 3.0.0 + bare-stream: 2.7.0(bare-events@2.8.2) + bare-url: 2.3.2 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + optional: true + + bare-os@3.6.2: + optional: true + + bare-path@3.0.0: + dependencies: + bare-os: 3.6.2 + optional: true + + bare-stream@2.7.0(bare-events@2.8.2): + dependencies: + streamx: 2.23.0 + optionalDependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + optional: true + + bare-url@2.3.2: + dependencies: + bare-path: 3.0.0 + optional: true + + base64-js@1.5.1: {} + + binary-extensions@2.3.0: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + body-scroll-lock@4.0.0-beta.0: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + bson-objectid@2.0.4: {} + + bson@6.10.4: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001760: {} + + ccount@2.0.1: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + charenc@0.0.2: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chownr@1.1.4: {} + + ci-info@4.3.1: {} + + classnames@2.5.1: {} + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.4 + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + + colorette@2.0.20: {} + + commander@2.20.3: {} + + concat-map@0.0.1: {} + + console-table-printer@2.12.1: + dependencies: + simple-wcswidth: 1.1.2 + + convert-source-map@1.9.0: {} + + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.1 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + + croner@9.0.0: {} + + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crypt@0.0.2: {} + + cssfilter@0.0.10: {} + + csstype@3.2.3: {} + + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + dataloader@2.2.3: {} + + date-fns@3.6.0: {} + + date-fns@4.1.0: {} + + dateformat@4.6.3: {} + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff@5.2.0: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.28.4 + csstype: 3.2.3 + + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + emoji-regex@9.2.2: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + esbuild@0.23.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-next@15.1.0(eslint@9.39.1)(typescript@5.7.2): + dependencies: + '@next/eslint-plugin-next': 15.1.0 + '@rushstack/eslint-patch': 1.15.0 + '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.2))(eslint@9.39.1)(typescript@5.7.2) + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.7.2) + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.1) + eslint-plugin-react: 7.37.5(eslint@9.39.1) + eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1) + optionalDependencies: + typescript: 5.7.2 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.39.1 + get-tsconfig: 4.13.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.15 + unrs-resolver: 1.11.1 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.7.2) + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.7.2) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.1): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.11.0 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.39.1 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@5.2.0(eslint@9.39.1): + dependencies: + eslint: 9.39.1 + + eslint-plugin-react@7.37.5(eslint@9.39.1): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.39.1 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.1: + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.3 + '@eslint/js': 9.39.1 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + esutils@2.0.3: {} + + events-universal@1.0.1: + dependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + + expand-template@2.0.3: {} + + fast-copy@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-fifo@1.3.2: {} + + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-redact@3.5.0: {} + + fast-safe-stringify@2.1.1: {} + + fast-uri@3.1.0: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + file-type@19.3.0: + dependencies: + strtok3: 8.1.0 + token-types: 6.1.1 + uint8array-extras: 1.5.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-root@1.1.0: {} + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + focus-trap@7.5.4: + dependencies: + tabbable: 6.3.0 + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + fs-constants@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + get-tsconfig@4.8.1: + dependencies: + resolve-pkg-maps: 1.0.0 + + github-from-package@0.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graphql-http@1.22.4(graphql@16.12.0): + dependencies: + graphql: 16.12.0 + + graphql-playground-html@1.6.30: + dependencies: + xss: 1.0.15 + + graphql-scalars@1.22.2(graphql@16.12.0): + dependencies: + graphql: 16.12.0 + tslib: 2.8.1 + + graphql@16.12.0: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + help-me@5.0.0: {} + + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + + http-status@1.6.2: {} + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + image-size@1.2.1: + dependencies: + queue: 6.0.2 + + immutable@4.3.7: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.2.1: {} + + is-arrayish@0.3.4: {} + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-buffer@1.1.6: {} + + is-bun-module@2.0.0: + dependencies: + semver: 7.7.3 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-decimal@2.0.1: {} + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + isomorphic.js@0.2.5: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jose@5.9.6: {} + + joycon@3.1.1: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-to-typescript@15.0.3: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.9.3 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.21 + is-glob: 4.0.3 + js-yaml: 4.1.1 + lodash: 4.17.21 + minimist: 1.2.8 + prettier: 3.7.4 + tinyglobby: 0.2.15 + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + kareem@2.6.3: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kleur@3.0.3: {} + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lexical@0.20.0: {} + + lib0@0.2.114: + dependencies: + isomorphic.js: 0.2.5 + + lines-and-columns@1.2.4: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash@4.17.21: {} + + longest-streak@3.1.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + marked@14.0.0: {} + + math-intrinsics@1.1.0: {} + + md5@2.3.0: + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.1.3: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + memoize-one@6.0.0: {} + + memory-pager@1.5.0: {} + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.1: + dependencies: + '@types/acorn': 4.0.6 + '@types/estree': 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mimic-response@3.1.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + mkdirp-classic@0.5.3: {} + + monaco-editor@0.55.1: + dependencies: + dompurify: 3.2.7 + marked: 14.0.0 + + mongodb-connection-string-url@3.0.2: + dependencies: + '@types/whatwg-url': 11.0.5 + whatwg-url: 14.2.0 + + mongodb@6.10.0: + dependencies: + '@mongodb-js/saslprep': 1.4.0 + bson: 6.10.4 + mongodb-connection-string-url: 3.0.2 + + mongoose-aggregate-paginate-v2@1.1.2: {} + + mongoose-paginate-v2@1.8.5: {} + + mongoose@8.8.3: + dependencies: + bson: 6.10.4 + kareem: 2.6.3 + mongodb: 6.10.0 + mpath: 0.9.0 + mquery: 5.0.0 + ms: 2.1.3 + sift: 17.1.3 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + - supports-color + + mpath@0.9.0: {} + + mquery@5.0.0: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + napi-build-utils@2.0.0: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + dependencies: + '@next/env': 15.4.9 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001760 + postcss: 8.4.31 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + styled-jsx: 5.1.6(react@19.2.1) + optionalDependencies: + '@next/swc-darwin-arm64': 15.4.8 + '@next/swc-darwin-x64': 15.4.8 + '@next/swc-linux-arm64-gnu': 15.4.8 + '@next/swc-linux-arm64-musl': 15.4.8 + '@next/swc-linux-x64-gnu': 15.4.8 + '@next/swc-linux-x64-musl': 15.4.8 + '@next/swc-win32-arm64-msvc': 15.4.8 + '@next/swc-win32-x64-msvc': 15.4.8 + sass: 1.77.4 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-abi@3.85.0: + dependencies: + semver: 7.7.3 + + node-addon-api@6.1.0: {} + + normalize-path@3.0.0: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object-to-formdata@4.5.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + on-exit-leak-free@2.1.2: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.2.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-to-regexp@6.3.0: {} + + path-type@4.0.0: {} + + payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2): + dependencies: + '@monaco-editor/react': 4.6.0(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@next/env': 15.5.8 + '@payloadcms/translations': 3.11.0 + '@types/busboy': 1.5.4 + ajv: 8.17.1 + bson-objectid: 2.0.4 + ci-info: 4.3.1 + console-table-printer: 2.12.1 + croner: 9.0.0 + dataloader: 2.2.3 + deepmerge: 4.3.1 + file-type: 19.3.0 + get-tsconfig: 4.8.1 + graphql: 16.12.0 + http-status: 1.6.2 + image-size: 1.2.1 + jose: 5.9.6 + json-schema-to-typescript: 15.0.3 + minimist: 1.2.8 + pino: 9.5.0 + pino-pretty: 13.0.0 + pluralize: 8.0.0 + sanitize-filename: 1.6.3 + scmp: 2.1.0 + ts-essentials: 10.0.3(typescript@5.7.2) + tsx: 4.19.2 + uuid: 10.0.0 + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - monaco-editor + - react + - react-dom + - typescript + - utf-8-validate + + peek-readable@5.4.2: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-pretty@13.0.0: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pump: 3.0.3 + secure-json-parse: 2.7.0 + sonic-boom: 4.2.0 + strip-json-comments: 3.1.1 + + pino-std-serializers@7.0.0: {} + + pino@9.5.0: + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 4.0.1 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + + pluralize@8.0.0: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.85.0 + pump: 3.0.3 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 + + prelude-ls@1.2.1: {} + + prettier@3.7.4: {} + + prismjs@1.30.0: {} + + process-warning@4.0.1: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + qs-esm@7.0.2: {} + + queue-microtask@1.2.3: {} + + queue@6.0.2: + dependencies: + inherits: 2.0.4 + + quick-format-unescaped@4.0.4: {} + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + react-datepicker@7.5.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + dependencies: + '@floating-ui/react': 0.26.28(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + clsx: 2.1.1 + date-fns: 3.6.0 + prop-types: 15.8.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + react-diff-viewer-continued@3.2.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + dependencies: + '@emotion/css': 11.13.5 + classnames: 2.5.1 + diff: 5.2.0 + memoize-one: 6.0.0 + prop-types: 15.8.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + transitivePeerDependencies: + - supports-color + + react-dom@19.2.1(react@19.2.1): + dependencies: + react: 19.2.1 + scheduler: 0.27.0 + + react-error-boundary@3.1.4(react@19.2.1): + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.1 + + react-error-boundary@4.1.2(react@19.2.1): + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.1 + + react-image-crop@10.1.8(react@19.2.1): + dependencies: + react: 19.2.1 + + react-is@16.13.1: {} + + react-select@5.9.0(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + dependencies: + '@babel/runtime': 7.28.4 + '@emotion/cache': 11.14.0 + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.1) + '@floating-ui/dom': 1.7.4 + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) + memoize-one: 6.0.0 + prop-types: 15.8.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.1)(react@19.2.1) + transitivePeerDependencies: + - '@types/react' + - supports-color + + react-transition-group@4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + dependencies: + '@babel/runtime': 7.28.4 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + react@19.2.1: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + real-require@0.2.0: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.5: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safe-stable-stringify@2.5.0: {} + + sanitize-filename@1.6.3: + dependencies: + truncate-utf8-bytes: 1.0.2 + + sass@1.77.4: + dependencies: + chokidar: 3.6.0 + immutable: 4.3.7 + source-map-js: 1.2.1 + + scheduler@0.25.0: {} + + scheduler@0.27.0: {} + + scmp@2.1.0: {} + + secure-json-parse@2.7.0: {} + + semver@6.3.1: {} + + semver@7.7.3: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + sharp@0.32.6: + dependencies: + color: 4.2.3 + detect-libc: 2.1.2 + node-addon-api: 6.1.0 + prebuild-install: 7.1.3 + semver: 7.7.3 + simple-get: 4.0.1 + tar-fs: 3.1.1 + tunnel-agent: 0.6.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + sharp@0.34.5: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + sift@17.1.3: {} + + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + + simple-wcswidth@1.1.2: {} + + sisteransi@1.0.5: {} + + sonic-boom@4.2.0: + dependencies: + atomic-sleep: 1.0.0 + + sonner@1.7.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + dependencies: + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + + source-map-js@1.2.1: {} + + source-map@0.5.7: {} + + sparse-bitfield@3.0.3: + dependencies: + memory-pager: 1.5.0 + + split2@4.2.0: {} + + stable-hash@0.0.5: {} + + state-local@1.0.7: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + streamsearch@1.1.0: {} + + streamx@2.23.0: + dependencies: + events-universal: 1.0.1 + fast-fifo: 1.3.2 + text-decoder: 1.2.3 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-bom@3.0.0: {} + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + strtok3@8.1.0: + dependencies: + '@tokenizer/token': 0.3.0 + peek-readable: 5.4.2 + + styled-jsx@5.1.6(react@19.2.1): + dependencies: + client-only: 0.0.1 + react: 19.2.1 + + stylis@4.2.0: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tabbable@6.3.0: {} + + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.3 + tar-stream: 2.2.0 + + tar-fs@3.1.1: + dependencies: + pump: 3.0.3 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 4.5.2 + bare-path: 3.0.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tar-stream@3.1.7: + dependencies: + b4a: 1.7.3 + fast-fifo: 1.3.2 + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + text-decoder@1.2.3: + dependencies: + b4a: 1.7.3 + transitivePeerDependencies: + - react-native-b4a + + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + token-types@6.1.1: + dependencies: + '@borewit/text-codec': 0.1.1 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + + truncate-utf8-bytes@1.0.2: + dependencies: + utf8-byte-length: 1.0.5 + + ts-api-utils@2.1.0(typescript@5.7.2): + dependencies: + typescript: 5.7.2 + + ts-essentials@10.0.3(typescript@5.7.2): + optionalDependencies: + typescript: 5.7.2 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + tsx@4.19.2: + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.8.1 + optionalDependencies: + fsevents: 2.3.3 + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript@5.7.2: {} + + uint8array-extras@1.5.0: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-context-selector@2.0.0(react@19.2.1)(scheduler@0.25.0): + dependencies: + react: 19.2.1 + scheduler: 0.25.0 + + use-isomorphic-layout-effect@1.2.1(@types/react@19.2.1)(react@19.2.1): + dependencies: + react: 19.2.1 + optionalDependencies: + '@types/react': 19.2.1 + + utf8-byte-length@1.0.5: {} + + util-deprecate@1.0.2: {} + + uuid@10.0.0: {} + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + webidl-conversions@7.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrappy@1.0.2: {} + + ws@8.18.3: {} + + xss@1.0.15: + dependencies: + commander: 2.20.3 + cssfilter: 0.0.10 + + yaml@1.10.2: {} + + yjs@13.6.27: + dependencies: + lib0: 0.2.114 + + yocto-queue@0.1.0: {} + + zwitch@2.0.4: {} diff --git a/examples/auth/package.json b/examples/auth/package.json index a5aae623fc6..2f632f2ca54 100644 --- a/examples/auth/package.json +++ b/examples/auth/package.json @@ -21,7 +21,7 @@ "@payloadcms/richtext-slate": "latest", "@payloadcms/ui": "latest", "cross-env": "^7.0.3", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "latest", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/examples/auth/pnpm-lock.yaml b/examples/auth/pnpm-lock.yaml index f470c8d816f..7decdd681f2 100644 --- a/examples/auth/pnpm-lock.yaml +++ b/examples/auth/pnpm-lock.yaml @@ -10,229 +10,122 @@ importers: dependencies: '@payloadcms/db-mongodb': specifier: latest - version: 3.9.0(@aws-sdk/credential-providers@3.556.0)(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(socks@2.8.3) + version: 3.68.2(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2)) '@payloadcms/next': specifier: latest - version: 3.9.0(@types/react@19.0.1)(graphql@16.8.1)(monaco-editor@0.48.0)(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) '@payloadcms/richtext-slate': specifier: latest - version: 3.9.0(@types/react@19.0.1)(monaco-editor@0.48.0)(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) '@payloadcms/ui': specifier: latest - version: 3.9.0(@types/react@19.0.1)(monaco-editor@0.48.0)(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) cross-env: specifier: ^7.0.3 version: 7.0.3 next: - specifier: ^15.0.0 - version: 15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + specifier: ^15.4.9 + version: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: latest - version: 3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.68.2(graphql@16.12.0)(typescript@5.5.2) react: - specifier: 19.0.0 - version: 19.0.0 + specifier: 19.2.1 + version: 19.2.1 react-dom: - specifier: 19.0.0 - version: 19.0.0(react@19.0.0) + specifier: 19.2.1 + version: 19.2.1(react@19.2.1) react-hook-form: specifier: ^7.51.3 - version: 7.51.3(react@19.0.0) + version: 7.68.0(react@19.2.1) devDependencies: '@payloadcms/graphql': specifier: latest - version: 3.9.0(graphql@16.8.1)(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(typescript@5.5.2) + version: 3.68.2(graphql@16.12.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(typescript@5.5.2) '@swc/core': specifier: ^1.6.13 - version: 1.10.1(@swc/helpers@0.5.15) + version: 1.15.3 '@types/ejs': specifier: ^3.1.5 version: 3.1.5 '@types/react': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1 '@types/react-dom': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) eslint: specifier: ^8.57.0 - version: 8.57.0 + version: 8.57.1 eslint-config-next: specifier: ^15.0.0 - version: 15.1.2(eslint@8.57.0)(typescript@5.5.2) + version: 15.5.8(eslint@8.57.1)(typescript@5.5.2) tsx: specifier: ^4.16.2 - version: 4.19.2 + version: 4.21.0 typescript: specifier: 5.5.2 version: 5.5.2 packages: - '@aashutoshrathi/word-wrap@1.2.6': - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - - '@apidevtools/json-schema-ref-parser@11.7.3': - resolution: {integrity: sha512-WApSdLdXEBb/1FUPca2lteASewEfpjEYJ8oXZP+0gExK5qSfsEKBKcA+WjY6Q4wvXwyv0+W6Kvc372pSceib9w==} + '@apidevtools/json-schema-ref-parser@11.9.3': + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} engines: {node: '>= 16'} - '@aws-crypto/ie11-detection@3.0.0': - resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} - - '@aws-crypto/sha256-browser@3.0.0': - resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} - - '@aws-crypto/sha256-js@3.0.0': - resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} - - '@aws-crypto/supports-web-crypto@3.0.0': - resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} - - '@aws-crypto/util@3.0.0': - resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} - - '@aws-sdk/client-cognito-identity@3.556.0': - resolution: {integrity: sha512-HWd7PyXCuY1Z9KBaufbzpIvS2QeUAak5wfYwylW2DrEvt6A4tjWCBSbbSXNoawqCv/HitA39v953N/1PojJVVQ==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/client-sso-oidc@3.556.0': - resolution: {integrity: sha512-AXKd2TB6nNrksu+OfmHl8uI07PdgzOo4o8AxoRO8SHlwoMAGvcT9optDGVSYoVfgOKTymCoE7h8/UoUfPc11wQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@aws-sdk/credential-provider-node': ^3.556.0 - - '@aws-sdk/client-sso@3.556.0': - resolution: {integrity: sha512-unXdWS7uvHqCcOyC1de+Fr8m3F2vMg2m24GPea0bg7rVGTYmiyn9mhUX11VCt+ozydrw+F50FQwL6OqoqPocmw==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/client-sts@3.556.0': - resolution: {integrity: sha512-TsK3js7Suh9xEmC886aY+bv0KdLLYtzrcmVt6sJ/W6EnDXYQhBuKYFhp03NrN2+vSvMGpqJwR62DyfKe1G0QzQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@aws-sdk/credential-provider-node': ^3.556.0 - - '@aws-sdk/core@3.556.0': - resolution: {integrity: sha512-vJaSaHw2kPQlo11j/Rzuz0gk1tEaKdz+2ser0f0qZ5vwFlANjt08m/frU17ctnVKC1s58bxpctO/1P894fHLrA==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-cognito-identity@3.556.0': - resolution: {integrity: sha512-PKYBjfpLHJZhrIv0M9eJ47yeDaV8NUMVe4vsiHG5tvlvwWGP84k9GJlr51U/s84OzIyXzVpiqP8PU5yKovUFIg==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-env@3.535.0': - resolution: {integrity: sha512-XppwO8c0GCGSAvdzyJOhbtktSEaShg14VJKg8mpMa1XcgqzmcqqHQjtDWbx5rZheY1VdpXZhpEzJkB6LpQejpA==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-http@3.552.0': - resolution: {integrity: sha512-vsmu7Cz1i45pFEqzVb4JcFmAmVnWFNLsGheZc8SCptlqCO5voETrZZILHYIl4cjKkSDk3pblBOf0PhyjqWW6WQ==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-ini@3.556.0': - resolution: {integrity: sha512-0Nz4ErOlXhe3muxWYMbPwRMgfKmVbBp36BAE2uv/z5wTbfdBkcgUwaflEvlKCLUTdHzuZsQk+BFS/gVyaUeOuA==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-node@3.556.0': - resolution: {integrity: sha512-s1xVtKjyGc60O8qcNIzS1X3H+pWEwEfZ7TgNznVDNyuXvLrlNWiAcigPWGl2aAkc8tGcsSG0Qpyw2KYC939LFg==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-process@3.535.0': - resolution: {integrity: sha512-9O1OaprGCnlb/kYl8RwmH7Mlg8JREZctB8r9sa1KhSsWFq/SWO0AuJTyowxD7zL5PkeS4eTvzFFHWCa3OO5epA==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-sso@3.556.0': - resolution: {integrity: sha512-ETuBgcnpfxqadEAqhQFWpKoV1C/NAgvs5CbBc5EJbelJ8f4prTdErIHjrRtVT8c02MXj92QwczsiNYd5IoOqyw==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-provider-web-identity@3.556.0': - resolution: {integrity: sha512-R/YAL8Uh8i+dzVjzMnbcWLIGeeRi2mioHVGnVF+minmaIkCiQMZg2HPrdlKm49El+RljT28Nl5YHRuiqzEIwMA==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/credential-providers@3.556.0': - resolution: {integrity: sha512-CnWP/AEF+sPeO8fabrHy4Oeo52xDFuDQMpjKcI7oJzGF6Ne2ZPTq6wTJQPLeXeg4OzLcK0tT3G4z/27MLdsLsw==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/middleware-host-header@3.535.0': - resolution: {integrity: sha512-0h6TWjBWtDaYwHMQJI9ulafeS4lLaw1vIxRjbpH0svFRt6Eve+Sy8NlVhECfTU2hNz/fLubvrUxsXoThaLBIew==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/middleware-logger@3.535.0': - resolution: {integrity: sha512-huNHpONOrEDrdRTvSQr1cJiRMNf0S52NDXtaPzdxiubTkP+vni2MohmZANMOai/qT0olmEVX01LhZ0ZAOgmg6A==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/middleware-recursion-detection@3.535.0': - resolution: {integrity: sha512-am2qgGs+gwqmR4wHLWpzlZ8PWhm4ktj5bYSgDrsOfjhdBlWNxvPoID9/pDAz5RWL48+oH7I6SQzMqxXsFDikrw==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/middleware-user-agent@3.540.0': - resolution: {integrity: sha512-8Rd6wPeXDnOYzWj1XCmOKcx/Q87L0K1/EHqOBocGjLVbN3gmRxBvpmR1pRTjf7IsWfnnzN5btqtcAkfDPYQUMQ==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/region-config-resolver@3.535.0': - resolution: {integrity: sha512-IXOznDiaItBjsQy4Fil0kzX/J3HxIOknEphqHbOfUf+LpA5ugcsxuQQONrbEQusCBnfJyymrldBvBhFmtlU9Wg==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/token-providers@3.556.0': - resolution: {integrity: sha512-tvIiugNF0/+2wfuImMrpKjXMx4nCnFWQjQvouObny+wrif/PGqqQYrybwxPJDvzbd965bu1I+QuSv85/ug7xsg==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/types@3.535.0': - resolution: {integrity: sha512-aY4MYfduNj+sRR37U7XxYR8wemfbKP6lx00ze2M2uubn7mZotuVrWYAafbMSXrdEMSToE5JDhr28vArSOoLcSg==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/util-endpoints@3.540.0': - resolution: {integrity: sha512-1kMyQFAWx6f8alaI6UT65/5YW/7pDWAKAdNwL6vuJLea03KrZRX3PMoONOSJpAS5m3Ot7HlWZvf3wZDNTLELZw==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/util-locate-window@3.535.0': - resolution: {integrity: sha512-PHJ3SL6d2jpcgbqdgiPxkXpu7Drc2PYViwxSIqvvMKhDwzSB1W3mMvtpzwKM4IE7zLFodZo0GKjJ9AsoXndXhA==} - engines: {node: '>=14.0.0'} - - '@aws-sdk/util-user-agent-browser@3.535.0': - resolution: {integrity: sha512-RWMcF/xV5n+nhaA/Ff5P3yNP3Kur/I+VNZngog4TEs92oB/nwOdAg/2JL8bVAhUbMrjTjpwm7PItziYFQoqyig==} + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} - '@aws-sdk/util-user-agent-node@3.535.0': - resolution: {integrity: sha512-dRek0zUuIT25wOWJlsRm97nTkUlh1NDcLsQZIN2Y8KxhwoXXWtJs5vaDPT+qAg+OpcNj80i1zLR/CirqlFg/TQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} - '@aws-sdk/util-utf8-browser@3.259.0': - resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} - '@babel/code-frame@7.24.2': - resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.24.3': - resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.24.1': - resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.22.20': - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.24.2': - resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.24.4': - resolution: {integrity: sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} - '@babel/types@7.24.0': - resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} - '@dnd-kit/accessibility@3.1.0': - resolution: {integrity: sha512-ea7IkhKvlJUv9iSHJOnxinBcoOI3ppGnnL+VDJ75O45Nss6HtZd8IdN8touXPDtASfeI2T2LImb8VOZcL47wjQ==} + '@borewit/text-codec@0.1.1': + resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} + + '@date-fns/tz@1.2.0': + resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==} + + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} peerDependencies: react: '>=16.8.0' @@ -253,26 +146,29 @@ packages: peerDependencies: react: '>=16.8.0' - '@emnapi/runtime@1.3.1': - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} - '@emotion/babel-plugin@11.11.0': - resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@emotion/cache@11.11.0': - resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==} + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} - '@emotion/css@11.11.2': - resolution: {integrity: sha512-VJxe1ucoMYMS7DkiMdC2T7PWNbrEI0a39YRiyDvK2qq4lXwjRbVP/z4lpG+odCsRzadlR+1ywwrTzhdm5HNdew==} + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} - '@emotion/hash@0.9.1': - resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} - '@emotion/memoize@0.8.1': - resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} - '@emotion/react@11.11.4': - resolution: {integrity: sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==} + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} peerDependencies: '@types/react': '*' react: '>=16.8.0' @@ -280,233 +176,399 @@ packages: '@types/react': optional: true - '@emotion/serialize@1.1.4': - resolution: {integrity: sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==} + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} - '@emotion/sheet@1.2.2': - resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==} + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} - '@emotion/unitless@0.8.1': - resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} - '@emotion/use-insertion-effect-with-fallbacks@1.0.1': - resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==} + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} peerDependencies: react: '>=16.8.0' - '@emotion/utils@1.2.1': - resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==} + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@emotion/weak-memoize@0.3.1': - resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] - '@esbuild/aix-ppc64@0.23.1': - resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + '@esbuild/aix-ppc64@0.27.1': + resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.23.1': - resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.27.1': + resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.23.1': - resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.23.1': - resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + '@esbuild/android-arm@0.27.1': + resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.23.1': - resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + '@esbuild/android-x64@0.27.1': + resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.27.1': + resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.23.1': - resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.23.1': - resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + '@esbuild/darwin-x64@0.27.1': + resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.1': + resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.23.1': - resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.1': + resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.23.1': - resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.23.1': - resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + '@esbuild/linux-arm64@0.27.1': + resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.23.1': - resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + '@esbuild/linux-arm@0.27.1': + resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.1': + resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.23.1': - resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.23.1': - resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + '@esbuild/linux-loong64@0.27.1': + resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.1': + resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.23.1': - resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.1': + resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.23.1': - resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.1': + resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.23.1': - resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.1': + resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.23.1': - resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-x64@0.23.1': - resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + '@esbuild/linux-x64@0.27.1': + resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==} engines: {node: '>=18'} cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] os: [netbsd] - '@esbuild/openbsd-arm64@0.23.1': - resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + '@esbuild/netbsd-arm64@0.27.1': + resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.1': + resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.1': + resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.23.1': - resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.23.1': - resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + '@esbuild/openbsd-x64@0.27.1': + resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.27.1': + resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.23.1': - resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + '@esbuild/sunos-x64@0.27.1': + resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.1': + resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.23.1': - resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.1': + resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.23.1': - resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.1': + resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.10.0': - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} '@eslint/eslintrc@2.1.4': resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@eslint/js@8.57.0': - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@faceless-ui/modal@3.0.0-beta.2': - resolution: {integrity: sha512-UmXvz7Iw3KMO4Pm3llZczU4uc5pPQDb6rdqwoBvYDFgWvkraOAHKx0HxSZgwqQvqOhn8joEFBfFp6/Do2562ow==} + '@faceless-ui/modal@3.0.0': + resolution: {integrity: sha512-o3oEFsot99EQ8RJc1kL3s/nNMHX+y+WMXVzSSmca9L0l2MR6ez2QM1z1yIelJX93jqkLXQ9tW+R9tmsYa+O4Qg==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@faceless-ui/scroll-info@2.0.0-beta.0': - resolution: {integrity: sha512-pUBhQP8vduA7rVndNsjhaCcds1BykA/Q4iV23JWijU6ZFL/M3Fm9P3ypDS+0VVxolqemNhw8S3FXPwZGgjH4Rw==} + '@faceless-ui/scroll-info@2.0.0': + resolution: {integrity: sha512-BkyJ9OQ4bzpKjE3UhI8BhcG36ZgfB4run8TmlaR4oMFUbl59dfyarNfjveyimrxIso9RhFEja/AJ5nQmbcR9hw==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@faceless-ui/window-info@3.0.0-beta.0': - resolution: {integrity: sha512-Qs8xRA+fl4sU2aFVe9xawxfi5TVZ9VTPuhdQpx9aSv7U5a2F0AXwT61lJfnaJ9Flm8tOcxzq67p8cVZsXNCVeQ==} + '@faceless-ui/window-info@3.0.1': + resolution: {integrity: sha512-uPjdJYE/j7hqVNelE9CRUNOeXuXDdPxR4DMe+oz3xwyZi2Y4CxsfpfdPTqqwmNAZa1P33O+ZiCyIkBEeNed0kw==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@floating-ui/core@1.6.0': - resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==} + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - '@floating-ui/dom@1.6.3': - resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - '@floating-ui/react-dom@2.1.2': - resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/react@0.26.28': - resolution: {integrity: sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==} + '@floating-ui/react@0.27.16': + resolution: {integrity: sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==} peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/utils@0.2.1': - resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} + react: '>=17.0.0' + react-dom: '>=17.0.0' - '@floating-ui/utils@0.2.8': - resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@humanwhocodes/config-array@0.11.14': - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} @@ -514,183 +576,230 @@ packages: '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jsdevtools/ono@7.1.3': resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} '@juggle/resize-observer@3.4.0': resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} - '@monaco-editor/loader@1.4.0': - resolution: {integrity: sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==} - peerDependencies: - monaco-editor: '>= 0.21.0 < 1' + '@monaco-editor/loader@1.7.0': + resolution: {integrity: sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==} - '@monaco-editor/react@4.6.0': - resolution: {integrity: sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==} + '@monaco-editor/react@4.7.0': + resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} peerDependencies: monaco-editor: '>= 0.25.0 < 1' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@mongodb-js/saslprep@1.4.0': + resolution: {integrity: sha512-ZHzx7Z3rdlWL1mECydvpryWN/ETXJiCxdgQKTAH+djzIPe77HdnSizKBDi1TVDXZjXyOj2IqEG/vPw71ULF06w==} - '@mongodb-js/saslprep@1.1.5': - resolution: {integrity: sha512-XLNOMH66KhJzUJNwT/qlMnS4WsNDWD5ASdyaSH3EtK+F4r/CFGa3jT4GNi4mfOitGvWXtdLgQJkQjxSVrio+jA==} + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@next/env@15.1.2': - resolution: {integrity: sha512-Hm3jIGsoUl6RLB1vzY+dZeqb+/kWPZ+h34yiWxW0dV87l8Im/eMOwpOA+a0L78U0HM04syEjXuRlCozqpwuojQ==} + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} - '@next/eslint-plugin-next@15.1.2': - resolution: {integrity: sha512-sgfw3+WdaYOGPKCvM1L+UucBmRfh8V2Ygefp7ELON0+0vY7uohQwXXnVWg3rY7mXDKharQR3o7uedpfvnU2hlQ==} + '@next/eslint-plugin-next@15.5.8': + resolution: {integrity: sha512-PBv6j6YxyC9cFgZKSGFlFydQ+lzzR3Fs1GBr9Z2YzoZK7dH/K8ebRtZiN4pV+b8MbSJiHjZYTKVPKF/UzNgrOA==} - '@next/swc-darwin-arm64@15.1.2': - resolution: {integrity: sha512-b9TN7q+j5/7+rGLhFAVZiKJGIASuo8tWvInGfAd8wsULjB1uNGRCj1z1WZwwPWzVQbIKWFYqc+9L7W09qwt52w==} + '@next/swc-darwin-arm64@15.5.7': + resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.1.2': - resolution: {integrity: sha512-caR62jNDUCU+qobStO6YJ05p9E+LR0EoXh1EEmyU69cYydsAy7drMcOlUlRtQihM6K6QfvNwJuLhsHcCzNpqtA==} + '@next/swc-darwin-x64@15.5.7': + resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.1.2': - resolution: {integrity: sha512-fHHXBusURjBmN6VBUtu6/5s7cCeEkuGAb/ZZiGHBLVBXMBy4D5QpM8P33Or8JD1nlOjm/ZT9sEE5HouQ0F+hUA==} + '@next/swc-linux-arm64-gnu@15.5.7': + resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.1.2': - resolution: {integrity: sha512-9CF1Pnivij7+M3G74lxr+e9h6o2YNIe7QtExWq1KUK4hsOLTBv6FJikEwCaC3NeYTflzrm69E5UfwEAbV2U9/g==} + '@next/swc-linux-arm64-musl@15.5.7': + resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.1.2': - resolution: {integrity: sha512-tINV7WmcTUf4oM/eN3Yuu/f8jQ5C6AkueZPKeALs/qfdfX57eNv4Ij7rt0SA6iZ8+fMobVfcFVv664Op0caCCg==} + '@next/swc-linux-x64-gnu@15.5.7': + resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.1.2': - resolution: {integrity: sha512-jf2IseC4WRsGkzeUw/cK3wci9pxR53GlLAt30+y+B+2qAQxMw6WAC3QrANIKxkcoPU3JFh/10uFfmoMDF9JXKg==} + '@next/swc-linux-x64-musl@15.5.7': + resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.1.2': - resolution: {integrity: sha512-wvg7MlfnaociP7k8lxLX4s2iBJm4BrNiNFhVUY+Yur5yhAJHfkS8qPPeDEUH8rQiY0PX3u/P7Q/wcg6Mv6GSAA==} + '@next/swc-win32-arm64-msvc@15.5.7': + resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.1.2': - resolution: {integrity: sha512-D3cNA8NoT3aWISWmo7HF5Eyko/0OdOO+VagkoJuiTk7pyX3P/b+n8XA/MYvyR+xSVcbKn68B1rY9fgqjNISqzQ==} + '@next/swc-win32-x64-msvc@15.5.7': + resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -711,268 +820,120 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} - '@payloadcms/db-mongodb@3.9.0': - resolution: {integrity: sha512-PysyhAv1QLLXhDb3SNCRgGEHD5Rwks87+5H1b4f+Cyp7/1aGVxAIE7rleJwJDZZjKI0DaETZrO7nmlFtD3JV2A==} + '@payloadcms/db-mongodb@3.68.2': + resolution: {integrity: sha512-UMofU0wabU9gmelV1v6/6fyecuZXp7CplH4B2zHbsukl02zQ6nKN1I1JLcFSAmAAg/FPDz/HkpHKM4zNuI0Rig==} peerDependencies: - payload: 3.9.0 + payload: 3.68.2 - '@payloadcms/graphql@3.9.0': - resolution: {integrity: sha512-QkrlcvmVI3x1bHzzDcf3LAQo5q2BRO+kFVIe+ruyz1qHupGtbbKCZzhjZYzti46MWBVEocoTO0krF2YmA5BTeQ==} + '@payloadcms/graphql@3.68.2': + resolution: {integrity: sha512-7RjoVXWgHmod7Dps24Z/0G8vXA0QUa+C2BL68gOnKBoWHsPB7PcaUp7luPizkW3jjfZLKnGkhvrI6CiD60bDsg==} hasBin: true peerDependencies: graphql: ^16.8.1 - payload: 3.9.0 + payload: 3.68.2 - '@payloadcms/next@3.9.0': - resolution: {integrity: sha512-/vu3kbZowEg4tSfFaOOwhKT65VHOTKyEeUpt8qMZsz9aggKdbEbJ+P59JlXT1kqJrpK4zvx4YRfiE+c6aPRpew==} + '@payloadcms/next@3.68.2': + resolution: {integrity: sha512-Pb3ZVPe3XbAJ3Th8nbyBnuaCMP4ZlockMczl2fyrethJ379pXPPBGjrFECPoaHhKjQPIEUVxo7WZjY8Yf/qBmg==} engines: {node: ^18.20.2 || >=20.9.0} peerDependencies: graphql: ^16.8.1 - next: ^15.0.0 - payload: 3.9.0 + next: ^15.4.8 + payload: 3.68.2 - '@payloadcms/richtext-slate@3.9.0': - resolution: {integrity: sha512-4omACG+Hj+t3FmJQHR/I/yjetTnzOieAlsSggRjxHZshlvi+tqemoSCGuMbRYTMe3d9/WraNMS2wV6U64/XsHg==} + '@payloadcms/richtext-slate@3.68.2': + resolution: {integrity: sha512-IWVEAk2FxsUvrhlZlP9n7+dQ2ywsnf3QsJ4xsuXQqAE1AiK9Y+iwVR66F1Vx8LqKviZrd8hCPCJnslh5jKua1w==} engines: {node: ^18.20.2 || >=20.9.0} peerDependencies: - payload: 3.9.0 - react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + payload: 3.68.2 + react: ^19.0.1 || ^19.1.2 || ^19.2.1 + react-dom: ^19.0.1 || ^19.1.2 || ^19.2.1 - '@payloadcms/translations@3.9.0': - resolution: {integrity: sha512-GN8tHKksO1s+jGA9GCWTdY1JDXV4PMl/RjPTrxjT+EhDRtk75OPm3nIdbBeBs/NlmpLYrISbjiRvV1fXjDBILA==} + '@payloadcms/translations@3.68.2': + resolution: {integrity: sha512-HIfB6QYknjFGHs83ynUYyRgyGRKAEE7DRF0VMscwX0RtXNEtg3DMM+bCyTu5AZXr1hWrQ4xUrnVh7Vaj1yqWFQ==} - '@payloadcms/ui@3.9.0': - resolution: {integrity: sha512-gWUdhYx3Wza5z+ea+TLVVgSe41VlsW7/HWR14tQHdUTGBRs/2qocW1pPMEx2aXEaJOTsXYeAyQRlmoyH45zu+w==} + '@payloadcms/ui@3.68.2': + resolution: {integrity: sha512-cKjdy0FucOTE+wxh5KZ7oTZQOvOxJFnmhfJd8av6HFoREt0r5kmnwc5rssdEgK2T1sJ2GcE4bZ0gVxB2vV6rCQ==} engines: {node: ^18.20.2 || >=20.9.0} peerDependencies: - next: ^15.0.0 - payload: 3.9.0 - react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 - react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + next: ^15.2.6 || ^15.3.6 || ^15.4.8 || ^15.5.7 + payload: 3.68.2 + react: ^19.0.1 || ^19.1.2 || ^19.2.1 + react-dom: ^19.0.1 || ^19.1.2 || ^19.2.1 + + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@rushstack/eslint-patch@1.10.4': - resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} - - '@smithy/abort-controller@2.2.0': - resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==} - engines: {node: '>=14.0.0'} - - '@smithy/config-resolver@2.2.0': - resolution: {integrity: sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==} - engines: {node: '>=14.0.0'} - - '@smithy/core@1.4.2': - resolution: {integrity: sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==} - engines: {node: '>=14.0.0'} - - '@smithy/credential-provider-imds@2.3.0': - resolution: {integrity: sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==} - engines: {node: '>=14.0.0'} - - '@smithy/fetch-http-handler@2.5.0': - resolution: {integrity: sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==} - - '@smithy/hash-node@2.2.0': - resolution: {integrity: sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==} - engines: {node: '>=14.0.0'} - - '@smithy/invalid-dependency@2.2.0': - resolution: {integrity: sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==} - - '@smithy/is-array-buffer@2.2.0': - resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-content-length@2.2.0': - resolution: {integrity: sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-endpoint@2.5.1': - resolution: {integrity: sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-retry@2.3.1': - resolution: {integrity: sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-serde@2.3.0': - resolution: {integrity: sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==} - engines: {node: '>=14.0.0'} - - '@smithy/middleware-stack@2.2.0': - resolution: {integrity: sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==} - engines: {node: '>=14.0.0'} - - '@smithy/node-config-provider@2.3.0': - resolution: {integrity: sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==} - engines: {node: '>=14.0.0'} - - '@smithy/node-http-handler@2.5.0': - resolution: {integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==} - engines: {node: '>=14.0.0'} - - '@smithy/property-provider@2.2.0': - resolution: {integrity: sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==} - engines: {node: '>=14.0.0'} - - '@smithy/protocol-http@3.3.0': - resolution: {integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==} - engines: {node: '>=14.0.0'} - - '@smithy/querystring-builder@2.2.0': - resolution: {integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==} - engines: {node: '>=14.0.0'} - - '@smithy/querystring-parser@2.2.0': - resolution: {integrity: sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==} - engines: {node: '>=14.0.0'} - - '@smithy/service-error-classification@2.1.5': - resolution: {integrity: sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==} - engines: {node: '>=14.0.0'} - - '@smithy/shared-ini-file-loader@2.4.0': - resolution: {integrity: sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==} - engines: {node: '>=14.0.0'} - - '@smithy/signature-v4@2.3.0': - resolution: {integrity: sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==} - engines: {node: '>=14.0.0'} - - '@smithy/smithy-client@2.5.1': - resolution: {integrity: sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==} - engines: {node: '>=14.0.0'} - - '@smithy/types@2.12.0': - resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==} - engines: {node: '>=14.0.0'} - - '@smithy/url-parser@2.2.0': - resolution: {integrity: sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==} - - '@smithy/util-base64@2.3.0': - resolution: {integrity: sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==} - engines: {node: '>=14.0.0'} - - '@smithy/util-body-length-browser@2.2.0': - resolution: {integrity: sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==} - - '@smithy/util-body-length-node@2.3.0': - resolution: {integrity: sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==} - engines: {node: '>=14.0.0'} - - '@smithy/util-buffer-from@2.2.0': - resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} - engines: {node: '>=14.0.0'} - - '@smithy/util-config-provider@2.3.0': - resolution: {integrity: sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==} - engines: {node: '>=14.0.0'} - - '@smithy/util-defaults-mode-browser@2.2.1': - resolution: {integrity: sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==} - engines: {node: '>= 10.0.0'} - - '@smithy/util-defaults-mode-node@2.3.1': - resolution: {integrity: sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==} - engines: {node: '>= 10.0.0'} + '@rushstack/eslint-patch@1.15.0': + resolution: {integrity: sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==} - '@smithy/util-endpoints@1.2.0': - resolution: {integrity: sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==} - engines: {node: '>= 14.0.0'} - - '@smithy/util-hex-encoding@2.2.0': - resolution: {integrity: sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==} - engines: {node: '>=14.0.0'} - - '@smithy/util-middleware@2.2.0': - resolution: {integrity: sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==} - engines: {node: '>=14.0.0'} - - '@smithy/util-retry@2.2.0': - resolution: {integrity: sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==} - engines: {node: '>= 14.0.0'} - - '@smithy/util-stream@2.2.0': - resolution: {integrity: sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==} - engines: {node: '>=14.0.0'} - - '@smithy/util-uri-escape@2.2.0': - resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==} - engines: {node: '>=14.0.0'} - - '@smithy/util-utf8@2.3.0': - resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} - engines: {node: '>=14.0.0'} - - '@swc/core-darwin-arm64@1.10.1': - resolution: {integrity: sha512-NyELPp8EsVZtxH/mEqvzSyWpfPJ1lugpTQcSlMduZLj1EASLO4sC8wt8hmL1aizRlsbjCX+r0PyL+l0xQ64/6Q==} + '@swc/core-darwin-arm64@1.15.3': + resolution: {integrity: sha512-AXfeQn0CvcQ4cndlIshETx6jrAM45oeUrK8YeEY6oUZU/qzz0Id0CyvlEywxkWVC81Ajpd8TQQ1fW5yx6zQWkQ==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.10.1': - resolution: {integrity: sha512-L4BNt1fdQ5ZZhAk5qoDfUnXRabDOXKnXBxMDJ+PWLSxOGBbWE6aJTnu4zbGjJvtot0KM46m2LPAPY8ttknqaZA==} + '@swc/core-darwin-x64@1.15.3': + resolution: {integrity: sha512-p68OeCz1ui+MZYG4wmfJGvcsAcFYb6Sl25H9TxWl+GkBgmNimIiRdnypK9nBGlqMZAcxngNPtnG3kEMNnvoJ2A==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.10.1': - resolution: {integrity: sha512-Y1u9OqCHgvVp2tYQAJ7hcU9qO5brDMIrA5R31rwWQIAKDkJKtv3IlTHF0hrbWk1wPR0ZdngkQSJZple7G+Grvw==} + '@swc/core-linux-arm-gnueabihf@1.15.3': + resolution: {integrity: sha512-Nuj5iF4JteFgwrai97mUX+xUOl+rQRHqTvnvHMATL/l9xE6/TJfPBpd3hk/PVpClMXG3Uvk1MxUFOEzM1JrMYg==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.10.1': - resolution: {integrity: sha512-tNQHO/UKdtnqjc7o04iRXng1wTUXPgVd8Y6LI4qIbHVoVPwksZydISjMcilKNLKIwOoUQAkxyJ16SlOAeADzhQ==} + '@swc/core-linux-arm64-gnu@1.15.3': + resolution: {integrity: sha512-2Nc/s8jE6mW2EjXWxO/lyQuLKShcmTrym2LRf5Ayp3ICEMX6HwFqB1EzDhwoMa2DcUgmnZIalesq2lG3krrUNw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.10.1': - resolution: {integrity: sha512-x0L2Pd9weQ6n8dI1z1Isq00VHFvpBClwQJvrt3NHzmR+1wCT/gcYl1tp9P5xHh3ldM8Cn4UjWCw+7PaUgg8FcQ==} + '@swc/core-linux-arm64-musl@1.15.3': + resolution: {integrity: sha512-j4SJniZ/qaZ5g8op+p1G9K1z22s/EYGg1UXIb3+Cg4nsxEpF5uSIGEE4mHUfA70L0BR9wKT2QF/zv3vkhfpX4g==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.10.1': - resolution: {integrity: sha512-yyYEwQcObV3AUsC79rSzN9z6kiWxKAVJ6Ntwq2N9YoZqSPYph+4/Am5fM1xEQYf/kb99csj0FgOelomJSobxQA==} + '@swc/core-linux-x64-gnu@1.15.3': + resolution: {integrity: sha512-aKttAZnz8YB1VJwPQZtyU8Uk0BfMP63iDMkvjhJzRZVgySmqt/apWSdnoIcZlUoGheBrcqbMC17GGUmur7OT5A==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.10.1': - resolution: {integrity: sha512-tcaS43Ydd7Fk7sW5ROpaf2Kq1zR+sI5K0RM+0qYLYYurvsJruj3GhBCaiN3gkzd8m/8wkqNqtVklWaQYSDsyqA==} + '@swc/core-linux-x64-musl@1.15.3': + resolution: {integrity: sha512-oe8FctPu1gnUsdtGJRO2rvOUIkkIIaHqsO9xxN0bTR7dFTlPTGi2Fhk1tnvXeyAvCPxLIcwD8phzKg6wLv9yug==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.10.1': - resolution: {integrity: sha512-D3Qo1voA7AkbOzQ2UGuKNHfYGKL6eejN8VWOoQYtGHHQi1p5KK/Q7V1ku55oxXBsj79Ny5FRMqiRJpVGad7bjQ==} + '@swc/core-win32-arm64-msvc@1.15.3': + resolution: {integrity: sha512-L9AjzP2ZQ/Xh58e0lTRMLvEDrcJpR7GwZqAtIeNLcTK7JVE+QineSyHp0kLkO1rttCHyCy0U74kDTj0dRz6raA==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.10.1': - resolution: {integrity: sha512-WalYdFoU3454Og+sDKHM1MrjvxUGwA2oralknXkXL8S0I/8RkWZOB++p3pLaGbTvOO++T+6znFbQdR8KRaa7DA==} + '@swc/core-win32-ia32-msvc@1.15.3': + resolution: {integrity: sha512-B8UtogMzErUPDWUoKONSVBdsgKYd58rRyv2sHJWKOIMCHfZ22FVXICR4O/VwIYtlnZ7ahERcjayBHDlBZpR0aw==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.10.1': - resolution: {integrity: sha512-JWobfQDbTnoqaIwPKQ3DVSywihVXlQMbDuwik/dDWlj33A8oEHcjPOGs4OqcA3RHv24i+lfCQpM3Mn4FAMfacA==} + '@swc/core-win32-x64-msvc@1.15.3': + resolution: {integrity: sha512-SpZKMR9QBTecHeqpzJdYEfgw30Oo8b/Xl6rjSzBt1g0ZsXyy60KLXrp6IagQyfTYqNYE/caDvwtF2FPn7pomog==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.10.1': - resolution: {integrity: sha512-rQ4dS6GAdmtzKiCRt3LFVxl37FaY1cgL9kSUTnhQ2xc3fmHOd7jdJK/V4pSZMG1ruGTd0bsi34O2R0Olg9Zo/w==} + '@swc/core@1.15.3': + resolution: {integrity: sha512-Qd8eBPkUFL4eAONgGjycZXj1jFCBW8Fd+xF0PzdTlBCWQIV1xnUT7B93wUANtW3KGjl3TRcOyxwSx/u/jyKw/Q==} engines: {node: '>=10'} peerDependencies: - '@swc/helpers': '*' + '@swc/helpers': '>=0.5.17' peerDependenciesMeta: '@swc/helpers': optional: true @@ -983,12 +944,15 @@ packages: '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@swc/types@0.1.17': - resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==} + '@swc/types@0.1.25': + resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==} '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/busboy@1.5.4': resolution: {integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==} @@ -1004,29 +968,30 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/lodash@4.17.0': - resolution: {integrity: sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==} + '@types/lodash@4.17.21': + resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} - '@types/lodash@4.17.13': - resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} - - '@types/node@20.12.7': - resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} + '@types/node@25.0.0': + resolution: {integrity: sha512-rl78HwuZlaDIUSeUKkmogkhebA+8K1Hy7tddZuJ3D0xV8pZSfsYGTsliGUol1JPzu9EKnTxPC4L1fiWouStRew==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/react-dom@19.0.1': - resolution: {integrity: sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 - '@types/react-transition-group@4.4.10': - resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==} + '@types/react-transition-group@4.4.12': + resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} + peerDependencies: + '@types/react': '*' - '@types/react@19.0.1': - resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} '@types/webidl-conversions@7.0.3': resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} @@ -1034,74 +999,170 @@ packages: '@types/whatwg-url@11.0.5': resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} - '@typescript-eslint/eslint-plugin@6.6.0': - resolution: {integrity: sha512-CW9YDGTQnNYMIo5lMeuiIG08p4E0cXrXTbcZ2saT/ETE7dWUrNxlijsQeU04qAAKkILiLzdQz+cGFxCJjaZUmA==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/eslint-plugin@8.49.0': + resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser': ^8.49.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@6.6.0': - resolution: {integrity: sha512-setq5aJgUwtzGrhW177/i+DMLqBaJbdwGj2CPIVFFLE0NCliy5ujIdLHd2D1ysmlmsjdL2GWW+hR85neEfc12w==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/parser@8.49.0': + resolution: {integrity: sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.49.0': + resolution: {integrity: sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@6.6.0': - resolution: {integrity: sha512-pT08u5W/GT4KjPUmEtc2kSYvrH8x89cVzkA0Sy2aaOUIw6YxOIjA8ilwLr/1fLjOedX1QAuBpG9XggWqIIfERw==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/scope-manager@8.49.0': + resolution: {integrity: sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@6.6.0': - resolution: {integrity: sha512-8m16fwAcEnQc69IpeDyokNO+D5spo0w1jepWWY2Q6y5ZKNuj5EhVQXjtVAeDDqvW6Yg7dhclbsz6rTtOvcwpHg==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/tsconfig-utils@8.49.0': + resolution: {integrity: sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@6.6.0': - resolution: {integrity: sha512-CB6QpJQ6BAHlJXdwUmiaXDBmTqIE2bzGTDLADgvqtHWuhfNP3rAOK7kAgRMAET5rDRr9Utt+qAzRBdu3AhR3sg==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/type-utils@8.49.0': + resolution: {integrity: sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/typescript-estree@6.6.0': - resolution: {integrity: sha512-hMcTQ6Al8MP2E6JKBAaSxSVw5bDhdmbCEhGW/V8QXkb9oNsFkA4SBuOMYVPxD3jbtQ4R/vSODBsr76R6fP3tbA==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/types@8.49.0': + resolution: {integrity: sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.49.0': + resolution: {integrity: sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@6.6.0': - resolution: {integrity: sha512-mPHFoNa2bPIWWglWYdR0QfY9GN0CfvvXX1Sv6DlSTive3jlMTUy+an67//Gysc+0Me9pjitrq0LJp0nGtLgftw==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/utils@8.49.0': + resolution: {integrity: sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.49.0': + resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] - '@typescript-eslint/visitor-keys@6.6.0': - resolution: {integrity: sha512-L61uJT26cMOfFQ+lMZKoJNbAEckLe539VhTxiGHrWl5XSKQgA0RTBZJW2HFPy5T0ZvPVSD93QsrTKDkfNwJGyQ==} - engines: {node: ^16.0.0 || >=18.0.0} + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] - '@ungap/structured-clone@1.2.0': - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true @@ -1115,10 +1176,6 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -1134,42 +1191,34 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} - array-buffer-byte-length@1.0.1: - resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} - array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - array.prototype.findlast@1.2.5: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} - array.prototype.findlastindex@1.2.5: - resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} engines: {node: '>= 0.4'} - array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} engines: {node: '>= 0.4'} - array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} engines: {node: '>= 0.4'} array.prototype.tosorted@1.1.4: resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} engines: {node: '>= 0.4'} - arraybuffer.prototype.slice@1.0.3: - resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} - engines: {node: '>= 0.4'} - arraybuffer.prototype.slice@1.0.4: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} @@ -1177,6 +1226,10 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + atomic-sleep@1.0.0: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} @@ -1185,8 +1238,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axe-core@4.10.2: - resolution: {integrity: sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==} + axe-core@4.11.0: + resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} engines: {node: '>=4'} axobject-query@4.1.0: @@ -1207,53 +1260,45 @@ packages: body-scroll-lock@4.0.0-beta.0: resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==} - bowser@2.11.0: - resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} bson-objectid@2.0.4: resolution: {integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==} - bson@6.10.1: - resolution: {integrity: sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==} + bson@6.10.4: + resolution: {integrity: sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==} engines: {node: '>=16.20.1'} busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} - call-bind-apply-helpers@1.0.1: - resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} - engines: {node: '>= 0.4'} - - call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} call-bind@1.0.8: resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} engines: {node: '>= 0.4'} - call-bound@1.0.3: - resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001612: - resolution: {integrity: sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==} - - chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} + caniuse-lite@1.0.30001760: + resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -1266,13 +1311,10 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} - ci-info@4.0.0: - resolution: {integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==} + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} engines: {node: '>=8'} - classnames@2.5.1: - resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} - client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} @@ -1280,26 +1322,13 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -1322,8 +1351,8 @@ packages: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} - croner@9.0.0: - resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==} + croner@9.1.0: + resolution: {integrity: sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==} engines: {node: '>=18.0'} cross-env@7.0.3: @@ -1331,8 +1360,8 @@ packages: engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} hasBin: true - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} crypt@0.0.2: @@ -1341,22 +1370,22 @@ packages: cssfilter@0.0.10: resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - data-view-buffer@1.0.1: - resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} - data-view-byte-length@1.0.1: - resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} engines: {node: '>= 0.4'} - data-view-byte-offset@1.0.0: - resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} dataloader@2.2.3: @@ -1379,17 +1408,8 @@ packages: supports-color: optional: true - debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -1416,16 +1436,8 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} - engines: {node: '>=8'} - - diff@5.2.0: - resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} - engines: {node: '>=0.3.1'} - - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} direction@1.0.4: @@ -1443,33 +1455,24 @@ packages: dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - - enhanced-resolve@5.17.1: - resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} - engines: {node: '>=10.13.0'} + engines: {node: '>= 0.4'} - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - es-abstract@1.23.3: - resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} - engines: {node: '>= 0.4'} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - es-abstract@1.23.6: - resolution: {integrity: sha512-Ifco6n3yj2tMZDWNLyloZrytt9lqqlwvS83P3HtaETR0NUOYnIULGGHpktqYGObGy+8wc1okO25p8TjemhImvA==} - engines: {node: '>= 0.4'} + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} es-define-property@1.0.1: @@ -1480,44 +1483,42 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-iterator-helpers@1.2.0: - resolution: {integrity: sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==} + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} - es-object-atoms@1.0.0: - resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} - - es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} engines: {node: '>= 0.4'} es-to-primitive@1.3.0: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - esbuild@0.23.1: - resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} hasBin: true - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} + esbuild@0.27.1: + resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==} + engines: {node: '>=18'} + hasBin: true escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-config-next@15.1.2: - resolution: {integrity: sha512-PrMm1/4zWSJ689wd/ypWIR5ZF1uvmp3EkgpgBV1Yu6PhEobBjXMGgT8bVNelwl17LXojO8D5ePFRiI4qXjsPRA==} + eslint-config-next@15.5.8: + resolution: {integrity: sha512-FU2nFCVYt3z60EH8upds4frThuIAiSt81zUtQI/9fIc25VVVT3yaKsFwGIY6BIDT/I0X/Dam+RR7xzTRZMyArQ==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 typescript: '>=3.3.1' @@ -1528,8 +1529,8 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-import-resolver-typescript@3.7.0: - resolution: {integrity: sha512-Vrwyi8HHxY97K5ebydMtffsWAn1SCR9eol49eCd5fJS4O1WV7PaAjbcjmbfJJSMz/t4Mal212Uz/fQZrOB8mow==} + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -1541,8 +1542,8 @@ packages: eslint-plugin-import-x: optional: true - eslint-module-utils@2.12.0: - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -1562,8 +1563,8 @@ packages: eslint-import-resolver-webpack: optional: true - eslint-plugin-import@2.31.0: - resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -1578,14 +1579,14 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - eslint-plugin-react-hooks@5.1.0: - resolution: {integrity: sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw==} + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react@7.37.2: - resolution: {integrity: sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==} + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 @@ -1598,17 +1599,22 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -1633,35 +1639,24 @@ packages: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} engines: {node: '>=8.6.0'} - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-redact@3.5.0: - resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} - engines: {node: '>=6'} - fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - fast-uri@3.0.3: - resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} - - fast-xml-parser@4.2.5: - resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} - hasBin: true + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} - fdir@6.4.2: - resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: @@ -1676,8 +1671,8 @@ packages: resolution: {integrity: sha512-mROwiKLZf/Kwa/2Rol+OOZQn1eyTkPB3ZTwC0ExY6OLFCbgxHYZvBm7xI77NvfZFMKBsmuXfmLJnD4eEftEhrA==} engines: {node: '>=18'} - fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} find-root@1.1.0: @@ -1691,14 +1686,15 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} - flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} focus-trap@7.5.4: resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} - for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -1711,29 +1707,32 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} - engines: {node: '>= 0.4'} - - function.prototype.name@1.1.7: - resolution: {integrity: sha512-2g4x+HqTJKM9zcJqBSpjoRmdcPFtJM60J3xJisTQSXBWka5XqyBN/2tNUgma1mztTXyDuUsEtYe5qcs7xYzYQA==} + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} engines: {node: '>= 0.4'} functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - get-intrinsic@1.2.6: - resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-symbol-description@1.0.2: - resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@4.8.1: resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} @@ -1747,38 +1746,25 @@ packages: glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} - globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} - globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - - gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - graphql-http@1.22.1: - resolution: {integrity: sha512-4Jor+LRbA7SfSaw7dfDUs2UBzvWg3cKrykfHRgKsOIvQaLuf+QOcG2t3Mx5N9GzSNJcuqMqJWz0ta5+BryEmXg==} + graphql-http@1.22.4: + resolution: {integrity: sha512-OC3ucK988teMf+Ak/O+ZJ0N2ukcgrEurypp8ePyJFWq83VzwRAmHxxr+XxrMpxO/FIwI4a7m/Fzv3tWGJv0wPA==} engines: {node: '>=12'} peerDependencies: graphql: '>=0.11 <=16' @@ -1792,16 +1778,13 @@ packages: peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - graphql@16.8.1: - resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} + graphql@16.12.0: + resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -1810,18 +1793,10 @@ packages: has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} - has-proto@1.2.0: resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} engines: {node: '>= 0.4'} - has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -1840,30 +1815,34 @@ packages: hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - http-status@1.6.2: - resolution: {integrity: sha512-oUExvfNckrpTpDazph7kNG8sQi5au3BeTo0idaZFXEhTaJKu7GNJCLHI0rYY2wljm548MSTM+Ljj/c6anqu2zQ==} + http-status@2.1.0: + resolution: {integrity: sha512-O5kPr7AW7wYd/BBiOezTwnVAnmSNFY+J7hlZD2X5IOxVBetjcHAiTXhzj0gMrnojQlwy+UT1/Y3H3vJ3UlmvLA==} engines: {node: '>= 0.4.0'} ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - image-size@1.1.1: - resolution: {integrity: sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==} + image-size@2.0.2: + resolution: {integrity: sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==} engines: {node: '>=16.x'} hasBin: true immer@9.0.21: resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} - immutable@4.3.5: - resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==} + immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} imurmurhash@0.1.4: @@ -1872,39 +1851,30 @@ packages: inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - internal-slot@1.0.7: - resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} - engines: {node: '>= 0.4'} - internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} - ip-address@9.0.5: - resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} - engines: {node: '>= 12'} + ipaddr.js@2.2.0: + resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} + engines: {node: '>= 10'} - is-array-buffer@3.0.4: - resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - - is-async-function@2.0.0: - resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} - is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} - is-bigint@1.1.0: resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} engines: {node: '>= 0.4'} @@ -1913,43 +1883,28 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} - - is-boolean-object@1.2.1: - resolution: {integrity: sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==} + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} is-buffer@1.1.6: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - is-bun-module@1.3.0: - resolution: {integrity: sha512-DgXeu5UWI0IsMQundYb5UAOzm6G2eVnarJ0byP6Tm55iZNKceD59LNPA2L4VvsScTtHcw0yEkVwSf7PC+QoLSA==} + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - - is-core-module@2.16.0: - resolution: {integrity: sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==} - engines: {node: '>= 0.4'} - - is-data-view@1.0.1: - resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} is-data-view@1.0.2: resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} engines: {node: '>= 0.4'} - is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} - is-date-object@1.1.0: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} @@ -1962,8 +1917,8 @@ packages: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} - is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} is-glob@4.0.3: @@ -1984,10 +1939,6 @@ packages: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} - is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} - is-number-object@1.1.1: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} @@ -2004,10 +1955,6 @@ packages: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} - is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} - is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -2016,30 +1963,18 @@ packages: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} - is-shared-array-buffer@1.0.3: - resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} - engines: {node: '>= 0.4'} - - is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} - is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} - is-symbol@1.1.1: resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} engines: {node: '>= 0.4'} - is-typed-array@1.1.13: - resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} - engines: {node: '>= 0.4'} - is-typed-array@1.1.15: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} @@ -2048,15 +1983,12 @@ packages: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} - is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - - is-weakref@1.1.0: - resolution: {integrity: sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==} + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} engines: {node: '>= 0.4'} - is-weakset@2.0.3: - resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} isarray@2.0.5: @@ -2065,8 +1997,8 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - iterator.prototype@1.1.4: - resolution: {integrity: sha512-x4WH0BWmrMmg4oHHl+duwubhrvczGlyuGAZu3nvrf0UXOfPu8IhZObFEr7DE/iv01YgVZrsOiRcqw2srkKEDIA==} + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} jose@5.9.6: @@ -2079,12 +2011,14 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -2125,8 +2059,8 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - language-subtag-registry@0.3.22: - resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} language-tags@1.0.9: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} @@ -2153,9 +2087,10 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} + marked@14.0.0: + resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} + engines: {node: '>= 18'} + hasBin: true math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} @@ -2174,28 +2109,32 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - monaco-editor@0.48.0: - resolution: {integrity: sha512-goSDElNqFfw7iDHMg8WDATkfcyeLTNpBHQpO8incK6p5qZt5G/1j41X0xdGzpIkGojGXM+QiRQyLjnfDVvrpwA==} + monaco-editor@0.55.1: + resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} - mongodb-connection-string-url@3.0.1: - resolution: {integrity: sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==} + mongodb-connection-string-url@3.0.2: + resolution: {integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==} - mongodb@6.10.0: - resolution: {integrity: sha512-gP9vduuYWb9ZkDM546M+MP2qKVk5ZG2wPF63OvSRuUbqCR+11ZCAE1mOfllhlAG0wcoJY5yDL/rV3OmYEwXIzg==} + mongodb@6.16.0: + resolution: {integrity: sha512-D1PNcdT0y4Grhou5Zi/qgipZOYeWrhLEpk33n3nm6LGtz61jvO88WlrWCK/bigMjpnOdAUKKQwsGIl0NtWMyYw==} engines: {node: '>=16.20.1'} peerDependencies: '@aws-sdk/credential-providers': ^3.188.0 - '@mongodb-js/zstd': ^1.1.0 + '@mongodb-js/zstd': ^1.1.0 || ^2.0.0 gcp-metadata: ^5.2.0 kerberos: ^2.0.1 mongodb-client-encryption: '>=6.0.0 <7' @@ -2217,16 +2156,12 @@ packages: socks: optional: true - mongoose-aggregate-paginate-v2@1.1.2: - resolution: {integrity: sha512-Ai478tHedZy3U2ITBEp2H4rQEviRan3TK4p/umlFqIzgPF1R0hNKvzzQGIb1l2h+Z32QLU3NqaoWKu4vOOUElQ==} - engines: {node: '>=4.0.0'} - mongoose-paginate-v2@1.8.5: resolution: {integrity: sha512-kFxhot+yw9KmpAGSSrF/o+f00aC2uawgNUbhyaM0USS9L7dln1NA77/pLg4lgOaRgXMtfgCENamjqZwIM1Zrig==} engines: {node: '>=4.0.0'} - mongoose@8.8.3: - resolution: {integrity: sha512-/I4n/DcXqXyIiLRfAmUIiTjj3vXfeISke8dt4U4Y8Wfm074Wa6sXnQrXN49NFOFf2mM1kUdOXryoBvkuCnr+Qw==} + mongoose@8.15.1: + resolution: {integrity: sha512-RhQ4DzmBi5BNGcS0w4u1vdMRIKcteXTCNzDt1j7XRcdWYBz1MjMjulBhPaeC5jBCHOD1yinuOFTTSOWLLGexWw==} engines: {node: '>=16.20.1'} mpath@0.9.0: @@ -2237,27 +2172,29 @@ packages: resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==} engines: {node: '>=14.0.0'} - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.1.2: - resolution: {integrity: sha512-nLJDV7peNy+0oHlmY2JZjzMfJ8Aj0/dd3jCwSZS8ZiO5nkQfcZRqDrRN3U5rJtqVTQneIOGZzb6LCNrk7trMCQ==} + next@15.5.8: + resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 + '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 @@ -2280,11 +2217,8 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - - object-inspect@1.13.3: - resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} object-keys@1.1.1: @@ -2294,12 +2228,12 @@ packages: object-to-formdata@4.5.1: resolution: {integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==} - object.assign@4.1.5: - resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} - object.entries@1.1.8: - resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} engines: {node: '>= 0.4'} object.fromentries@2.0.8: @@ -2310,8 +2244,8 @@ packages: resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} - object.values@1.2.0: - resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} on-exit-leak-free@2.1.2: @@ -2321,10 +2255,14 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -2356,55 +2294,55 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-to-regexp@6.2.2: - resolution: {integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - payload@3.9.0: - resolution: {integrity: sha512-7RYx64ZHyEXJCgNpzGBgzpwDYCBRQUqKhfB8FhozQQ6OHn9uOHTn6htUngfx0/d0ijSdoDsK8cyMFD09xUfuPw==} + payload@3.68.2: + resolution: {integrity: sha512-4ZdTJOUKSwUJXXMgEYIjonWmAgTxfnGTMuqQ1FZneSrZoZyjMOvXGiStEM0Ejd4zOlctUtAfum/gdgQC/CExyg==} engines: {node: ^18.20.2 || >=20.9.0} hasBin: true peerDependencies: graphql: ^16.8.1 - peek-readable@5.3.1: - resolution: {integrity: sha512-GVlENSDW6KHaXcd9zkZltB7tCLosKB/4Hg0fqBJkAoBgYG2Tn1xtMgXtSUuMU9AK/gCm/tTdT8mgAeF4YNeeqw==} + peek-readable@5.4.2: + resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} engines: {node: '>=14.16'} - picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} pino-abstract-transport@2.0.0: resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} - pino-pretty@13.0.0: - resolution: {integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==} + pino-pretty@13.1.2: + resolution: {integrity: sha512-3cN0tCakkT4f3zo9RXDIhy6GTvtYD6bK4CRBLN9j3E/ePqN1tugAXD5rGVfoChW6s0hiek+eyYlLNqc/BG7vBQ==} hasBin: true pino-std-serializers@7.0.0: resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} - pino@9.5.0: - resolution: {integrity: sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==} + pino@9.14.0: + resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} hasBin: true pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} - possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} postcss@8.4.31: @@ -2415,13 +2353,13 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.4.2: - resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==} + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} engines: {node: '>=14'} hasBin: true - process-warning@4.0.0: - resolution: {integrity: sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==} + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} @@ -2430,8 +2368,8 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - pump@3.0.0: - resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} @@ -2444,35 +2382,25 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - queue@6.0.2: - resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} - quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - react-datepicker@7.5.0: - resolution: {integrity: sha512-6MzeamV8cWSOcduwePHfGqY40acuGlS1cG//ePHT6bVbLxWyqngaStenfH03n1wbzOibFggF66kWaBTb1SbTtQ==} - peerDependencies: - react: ^16.9.0 || ^17 || ^18 - react-dom: ^16.9.0 || ^17 || ^18 - - react-diff-viewer-continued@3.2.6: - resolution: {integrity: sha512-GrzyqQnjIMoej+jMjWvtVSsQqhXgzEGqpXlJ2dAGfOk7Q26qcm8Gu6xtI430PBUyZsERe8BJSQf+7VZZo8IBNQ==} - engines: {node: '>= 8'} + react-datepicker@7.6.0: + resolution: {integrity: sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==} peerDependencies: - react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc - react-dom@19.0.0: - resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + react-dom@19.2.1: + resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==} peerDependencies: - react: ^19.0.0 + react: ^19.2.1 - react-hook-form@7.51.3: - resolution: {integrity: sha512-cvJ/wbHdhYx8aviSWh28w9ImjmVsb5Y05n1+FW786vEZQJV5STNM0pW6ujS+oiBecb0ARBxJFyAnXj9+GHXACQ==} - engines: {node: '>=12.22.0'} + react-hook-form@7.68.0: + resolution: {integrity: sha512-oNN3fjrZ/Xo40SWlHf1yCjlMK417JxoSJVUXQjGdvdRCU07NTFei1i1f8ApUAts+IVh14e4EdakeLEA+BEAs/Q==} + engines: {node: '>=18.0.0'} peerDependencies: - react: ^16.8.0 || ^17 || ^18 + react: ^16.8.0 || ^17 || ^18 || ^19 react-image-crop@10.1.8: resolution: {integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==} @@ -2494,8 +2422,8 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' - react@19.0.0: - resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} + react@19.2.1: + resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==} engines: {node: '>=0.10.0'} readdirp@3.6.0: @@ -2506,19 +2434,12 @@ packages: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} - reflect.getprototypeof@1.0.9: - resolution: {integrity: sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==} - engines: {node: '>= 0.4'} - - regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - - regexp.prototype.flags@1.5.2: - resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} - regexp.prototype.flags@1.5.3: - resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} require-from-string@2.0.2: @@ -2532,43 +2453,41 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} hasBin: true resolve@2.0.0-next.5: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - safe-array-concat@1.1.2: - resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} - engines: {node: '>=0.4'} - safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} - safe-regex-test@1.0.3: - resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} safe-regex-test@1.1.0: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} - safe-stable-stringify@2.4.3: - resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} engines: {node: '>=10'} sanitize-filename@1.6.3: @@ -2582,26 +2501,24 @@ packages: scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + scmp@2.1.0: resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} scroll-into-view-if-needed@2.2.31: resolution: {integrity: sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==} - secure-json-parse@2.7.0: - resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + secure-json-parse@4.1.0: + resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} - engines: {node: '>=10'} - hasBin: true - - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true @@ -2613,8 +2530,12 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -2637,10 +2558,6 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} - engines: {node: '>= 0.4'} - side-channel@1.1.0: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} @@ -2648,19 +2565,12 @@ packages: sift@17.1.3: resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - - simple-wcswidth@1.0.1: - resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==} + simple-wcswidth@1.1.2: + resolution: {integrity: sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==} sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - slate-history@0.86.0: resolution: {integrity: sha512-OxObL9tbhgwvSlnKSCpGIh7wnuaqvOj5jRExGjEyCU2Ke8ctf22HjT+jw7GEi9ttLzNTUmTEU3YIzqKGeqN+og==} peerDependencies: @@ -2681,25 +2591,17 @@ packages: slate@0.91.4: resolution: {integrity: sha512-aUJ3rpjrdi5SbJ5G1Qjr3arytfRkEStTmHjBfWq2A2Q8MybacIzkScSvGJjQkdTk3djCK9C9SEOt39sSeZFwTw==} - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - - socks@2.8.3: - resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - sonic-boom@4.2.0: resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} - sonner@1.7.1: - resolution: {integrity: sha512-b6LHBfH32SoVasRFECrdY8p8s7hXPDn3OHUFbZZbiB1ctLS9Gdh6rpX2dVrpQA0kiL5jcRzDDldwwLkSKk3+QQ==} + sonner@1.7.4: + resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} peerDependencies: react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} source-map@0.5.7: @@ -2713,15 +2615,16 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} - sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - - stable-hash@0.0.4: - resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} state-local@1.0.7: resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -2730,8 +2633,8 @@ packages: resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} engines: {node: '>= 0.4'} - string.prototype.matchall@4.0.11: - resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} string.prototype.repeat@1.0.0: @@ -2741,13 +2644,6 @@ packages: resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} - string.prototype.trim@1.2.9: - resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.8: - resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} - string.prototype.trimend@1.0.9: resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} engines: {node: '>= 0.4'} @@ -2768,8 +2664,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strnum@1.0.5: - resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} strtok3@8.1.0: resolution: {integrity: sha512-ExzDvHYPj6F6QkSNe/JxSlBxTh3OrI6wrAIz53ulxo1c4hBJ1bT9C/JrAthEKHWG9riVH3Xzg7B03Oxty6S2Lw==} @@ -2791,10 +2688,6 @@ packages: stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2803,12 +2696,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - tabbable@6.2.0: - resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} - - tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} - engines: {node: '>=6'} + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -2822,34 +2711,30 @@ packages: tiny-warning@1.0.3: resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - tinyglobby@0.2.10: - resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - token-types@6.0.0: - resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==} + token-types@6.1.1: + resolution: {integrity: sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ==} engines: {node: '>=14.16'} - tr46@4.1.1: - resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} - engines: {node: '>=14'} + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} truncate-utf8-bytes@1.0.2: resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} peerDependencies: - typescript: '>=4.2.0' + typescript: '>=4.8.4' ts-essentials@10.0.3: resolution: {integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==} @@ -2862,17 +2747,21 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - - tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.19.2: - resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} + tsx@4.20.3: + resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==} + engines: {node: '>=18.0.0'} + hasBin: true + + tsx@4.20.6: + resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + engines: {node: '>=18.0.0'} + hasBin: true + + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} hasBin: true @@ -2884,26 +2773,18 @@ packages: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} - typed-array-buffer@1.0.2: - resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.1: - resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} - typed-array-byte-offset@1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} engines: {node: '>= 0.4'} typed-array-byte-offset@1.0.4: resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} engines: {node: '>= 0.4'} - typed-array-length@1.0.6: - resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} - engines: {node: '>= 0.4'} - typed-array-length@1.0.7: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} @@ -2913,15 +2794,23 @@ packages: engines: {node: '>=14.17'} hasBin: true - uint8array-extras@1.4.0: - resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==} + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} engines: {node: '>=18'} - unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + undici@7.10.0: + resolution: {integrity: sha512-u5otvFBOBZvmdjWLVW+5DAc9Nkq8f24g0O9oY7qw2JVIF1VocIFoyz9JFkuVOS2j41AufeO0xnlweJ2RLT8nGw==} + engines: {node: '>=20.18.1'} - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -2932,8 +2821,8 @@ packages: react: '>=18.0.0' scheduler: '>=0.19.0' - use-isomorphic-layout-effect@1.2.0: - resolution: {integrity: sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==} + use-isomorphic-layout-effect@1.2.1: + resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} peerDependencies: '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -2941,27 +2830,20 @@ packages: '@types/react': optional: true - utf8-byte-length@1.0.4: - resolution: {integrity: sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==} + utf8-byte-length@1.0.5: + resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} - whatwg-url@13.0.0: - resolution: {integrity: sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==} - engines: {node: '>=16'} - - which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} @@ -2975,12 +2857,8 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} - which-typed-array@1.1.15: - resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} - engines: {node: '>= 0.4'} - - which-typed-array@1.1.18: - resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} engines: {node: '>= 0.4'} which@2.0.2: @@ -2988,11 +2866,15 @@ packages: engines: {node: '>= 8'} hasBin: true + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.16.0: - resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -3008,9 +2890,6 @@ packages: engines: {node: '>= 0.10.0'} hasBin: true - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} @@ -3021,734 +2900,403 @@ packages: snapshots: - '@aashutoshrathi/word-wrap@1.2.6': {} - - '@apidevtools/json-schema-ref-parser@11.7.3': + '@apidevtools/json-schema-ref-parser@11.9.3': dependencies: '@jsdevtools/ono': 7.1.3 '@types/json-schema': 7.0.15 - js-yaml: 4.1.0 - - '@aws-crypto/ie11-detection@3.0.0': - dependencies: - tslib: 1.14.1 - optional: true + js-yaml: 4.1.1 - '@aws-crypto/sha256-browser@3.0.0': + '@babel/code-frame@7.27.1': dependencies: - '@aws-crypto/ie11-detection': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-crypto/supports-web-crypto': 3.0.0 - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-locate-window': 3.535.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - optional: true + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@aws-crypto/sha256-js@3.0.0': + '@babel/generator@7.28.5': dependencies: - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.535.0 - tslib: 1.14.1 - optional: true + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 - '@aws-crypto/supports-web-crypto@3.0.0': - dependencies: - tslib: 1.14.1 - optional: true + '@babel/helper-globals@7.28.0': {} - '@aws-crypto/util@3.0.0': + '@babel/helper-module-imports@7.27.1': dependencies: - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - optional: true - - '@aws-sdk/client-cognito-identity@3.556.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/core': 3.556.0 - '@aws-sdk/credential-provider-node': 3.556.0 - '@aws-sdk/middleware-host-header': 3.535.0 - '@aws-sdk/middleware-logger': 3.535.0 - '@aws-sdk/middleware-recursion-detection': 3.535.0 - '@aws-sdk/middleware-user-agent': 3.540.0 - '@aws-sdk/region-config-resolver': 3.535.0 - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-endpoints': 3.540.0 - '@aws-sdk/util-user-agent-browser': 3.535.0 - '@aws-sdk/util-user-agent-node': 3.535.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - - aws-crt - optional: true + - supports-color - '@aws-sdk/client-sso-oidc@3.556.0(@aws-sdk/credential-provider-node@3.556.0)': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/core': 3.556.0 - '@aws-sdk/credential-provider-node': 3.556.0 - '@aws-sdk/middleware-host-header': 3.535.0 - '@aws-sdk/middleware-logger': 3.535.0 - '@aws-sdk/middleware-recursion-detection': 3.535.0 - '@aws-sdk/middleware-user-agent': 3.540.0 - '@aws-sdk/region-config-resolver': 3.535.0 - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-endpoints': 3.540.0 - '@aws-sdk/util-user-agent-browser': 3.535.0 - '@aws-sdk/util-user-agent-node': 3.535.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - optional: true + '@babel/helper-string-parser@7.27.1': {} - '@aws-sdk/client-sso@3.556.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.556.0 - '@aws-sdk/middleware-host-header': 3.535.0 - '@aws-sdk/middleware-logger': 3.535.0 - '@aws-sdk/middleware-recursion-detection': 3.535.0 - '@aws-sdk/middleware-user-agent': 3.540.0 - '@aws-sdk/region-config-resolver': 3.535.0 - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-endpoints': 3.540.0 - '@aws-sdk/util-user-agent-browser': 3.535.0 - '@aws-sdk/util-user-agent-node': 3.535.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - optional: true + '@babel/helper-validator-identifier@7.28.5': {} - '@aws-sdk/client-sts@3.556.0(@aws-sdk/credential-provider-node@3.556.0)': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.556.0 - '@aws-sdk/credential-provider-node': 3.556.0 - '@aws-sdk/middleware-host-header': 3.535.0 - '@aws-sdk/middleware-logger': 3.535.0 - '@aws-sdk/middleware-recursion-detection': 3.535.0 - '@aws-sdk/middleware-user-agent': 3.540.0 - '@aws-sdk/region-config-resolver': 3.535.0 - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-endpoints': 3.540.0 - '@aws-sdk/util-user-agent-browser': 3.535.0 - '@aws-sdk/util-user-agent-node': 3.535.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - optional: true + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 - '@aws-sdk/core@3.556.0': + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': dependencies: - '@smithy/core': 1.4.2 - '@smithy/protocol-http': 3.3.0 - '@smithy/signature-v4': 2.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - fast-xml-parser: 4.2.5 - tslib: 2.6.2 - optional: true + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 - '@aws-sdk/credential-provider-cognito-identity@3.556.0': + '@babel/traverse@7.28.5': dependencies: - '@aws-sdk/client-cognito-identity': 3.556.0 - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 transitivePeerDependencies: - - aws-crt - optional: true + - supports-color - '@aws-sdk/credential-provider-env@3.535.0': + '@babel/types@7.28.5': dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true - - '@aws-sdk/credential-provider-http@3.552.0': - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/property-provider': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 - optional: true + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 - '@aws-sdk/credential-provider-ini@3.556.0(@aws-sdk/credential-provider-node@3.556.0)': - dependencies: - '@aws-sdk/client-sts': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/credential-provider-env': 3.535.0 - '@aws-sdk/credential-provider-process': 3.535.0 - '@aws-sdk/credential-provider-sso': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/credential-provider-web-identity': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/types': 3.535.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/credential-provider-node' - - aws-crt - optional: true + '@borewit/text-codec@0.1.1': {} - '@aws-sdk/credential-provider-node@3.556.0': - dependencies: - '@aws-sdk/credential-provider-env': 3.535.0 - '@aws-sdk/credential-provider-http': 3.552.0 - '@aws-sdk/credential-provider-ini': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/credential-provider-process': 3.535.0 - '@aws-sdk/credential-provider-sso': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/credential-provider-web-identity': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/types': 3.535.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - optional: true + '@date-fns/tz@1.2.0': {} - '@aws-sdk/credential-provider-process@3.535.0': + '@dnd-kit/accessibility@3.1.1(react@19.2.1)': dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + react: 19.2.1 + tslib: 2.8.1 - '@aws-sdk/credential-provider-sso@3.556.0(@aws-sdk/credential-provider-node@3.556.0)': + '@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - '@aws-sdk/client-sso': 3.556.0 - '@aws-sdk/token-providers': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/credential-provider-node' - - aws-crt - optional: true + '@dnd-kit/accessibility': 3.1.1(react@19.2.1) + '@dnd-kit/utilities': 3.2.2(react@19.2.1) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + tslib: 2.8.1 - '@aws-sdk/credential-provider-web-identity@3.556.0(@aws-sdk/credential-provider-node@3.556.0)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': dependencies: - '@aws-sdk/client-sts': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/credential-provider-node' - - aws-crt - optional: true + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/utilities': 3.2.2(react@19.2.1) + react: 19.2.1 + tslib: 2.8.1 - '@aws-sdk/credential-providers@3.556.0': - dependencies: - '@aws-sdk/client-cognito-identity': 3.556.0 - '@aws-sdk/client-sso': 3.556.0 - '@aws-sdk/client-sts': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/credential-provider-cognito-identity': 3.556.0 - '@aws-sdk/credential-provider-env': 3.535.0 - '@aws-sdk/credential-provider-http': 3.552.0 - '@aws-sdk/credential-provider-ini': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/credential-provider-node': 3.556.0 - '@aws-sdk/credential-provider-process': 3.535.0 - '@aws-sdk/credential-provider-sso': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/credential-provider-web-identity': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/types': 3.535.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - optional: true + '@dnd-kit/utilities@3.2.2(react@19.2.1)': + dependencies: + react: 19.2.1 + tslib: 2.8.1 - '@aws-sdk/middleware-host-header@3.535.0': + '@emnapi/core@1.7.1': dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 optional: true - '@aws-sdk/middleware-logger@3.535.0': + '@emnapi/runtime@1.7.1': dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 optional: true - '@aws-sdk/middleware-recursion-detection@3.535.0': + '@emnapi/wasi-threads@1.1.0': dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 optional: true - '@aws-sdk/middleware-user-agent@3.540.0': + '@emotion/babel-plugin@11.13.5': dependencies: - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-endpoints': 3.540.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@babel/helper-module-imports': 7.27.1 + '@babel/runtime': 7.28.4 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color - '@aws-sdk/region-config-resolver@3.535.0': + '@emotion/cache@11.14.0': dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-config-provider': 2.3.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - optional: true + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/hash@0.9.2': {} - '@aws-sdk/token-providers@3.556.0(@aws-sdk/credential-provider-node@3.556.0)': + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.1)': dependencies: - '@aws-sdk/client-sso-oidc': 3.556.0(@aws-sdk/credential-provider-node@3.556.0) - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@babel/runtime': 7.28.4 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.1) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.1 + optionalDependencies: + '@types/react': 19.2.1 transitivePeerDependencies: - - '@aws-sdk/credential-provider-node' - - aws-crt - optional: true + - supports-color - '@aws-sdk/types@3.535.0': + '@emotion/serialize@1.3.3': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.2.3 - '@aws-sdk/util-endpoints@3.540.0': - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/types': 2.12.0 - '@smithy/util-endpoints': 1.2.0 - tslib: 2.6.2 - optional: true + '@emotion/sheet@1.4.0': {} - '@aws-sdk/util-locate-window@3.535.0': + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.1)': dependencies: - tslib: 2.6.2 + react: 19.2.1 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + + '@esbuild/aix-ppc64@0.25.12': optional: true - '@aws-sdk/util-user-agent-browser@3.535.0': - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/types': 2.12.0 - bowser: 2.11.0 - tslib: 2.6.2 + '@esbuild/aix-ppc64@0.27.1': optional: true - '@aws-sdk/util-user-agent-node@3.535.0': - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@esbuild/android-arm64@0.25.12': optional: true - '@aws-sdk/util-utf8-browser@3.259.0': - dependencies: - tslib: 2.6.2 + '@esbuild/android-arm64@0.27.1': optional: true - '@babel/code-frame@7.24.2': - dependencies: - '@babel/highlight': 7.24.2 - picocolors: 1.0.0 + '@esbuild/android-arm@0.25.12': + optional: true - '@babel/helper-module-imports@7.24.3': - dependencies: - '@babel/types': 7.24.0 + '@esbuild/android-arm@0.27.1': + optional: true - '@babel/helper-string-parser@7.24.1': {} + '@esbuild/android-x64@0.25.12': + optional: true - '@babel/helper-validator-identifier@7.22.20': {} + '@esbuild/android-x64@0.27.1': + optional: true - '@babel/highlight@7.24.2': - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.0.0 + '@esbuild/darwin-arm64@0.25.12': + optional: true - '@babel/runtime@7.24.4': - dependencies: - regenerator-runtime: 0.14.1 + '@esbuild/darwin-arm64@0.27.1': + optional: true - '@babel/types@7.24.0': - dependencies: - '@babel/helper-string-parser': 7.24.1 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 + '@esbuild/darwin-x64@0.25.12': + optional: true - '@dnd-kit/accessibility@3.1.0(react@19.0.0)': - dependencies: - react: 19.0.0 - tslib: 2.6.2 + '@esbuild/darwin-x64@0.27.1': + optional: true - '@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@dnd-kit/accessibility': 3.1.0(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - tslib: 2.6.2 + '@esbuild/freebsd-arm64@0.25.12': + optional: true - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': - dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 - tslib: 2.6.2 + '@esbuild/freebsd-arm64@0.27.1': + optional: true - '@dnd-kit/utilities@3.2.2(react@19.0.0)': - dependencies: - react: 19.0.0 - tslib: 2.6.2 + '@esbuild/freebsd-x64@0.25.12': + optional: true - '@emnapi/runtime@1.3.1': - dependencies: - tslib: 2.6.2 + '@esbuild/freebsd-x64@0.27.1': optional: true - '@emotion/babel-plugin@11.11.0': - dependencies: - '@babel/helper-module-imports': 7.24.3 - '@babel/runtime': 7.24.4 - '@emotion/hash': 0.9.1 - '@emotion/memoize': 0.8.1 - '@emotion/serialize': 1.1.4 - babel-plugin-macros: 3.1.0 - convert-source-map: 1.9.0 - escape-string-regexp: 4.0.0 - find-root: 1.1.0 - source-map: 0.5.7 - stylis: 4.2.0 + '@esbuild/linux-arm64@0.25.12': + optional: true - '@emotion/cache@11.11.0': - dependencies: - '@emotion/memoize': 0.8.1 - '@emotion/sheet': 1.2.2 - '@emotion/utils': 1.2.1 - '@emotion/weak-memoize': 0.3.1 - stylis: 4.2.0 + '@esbuild/linux-arm64@0.27.1': + optional: true - '@emotion/css@11.11.2': - dependencies: - '@emotion/babel-plugin': 11.11.0 - '@emotion/cache': 11.11.0 - '@emotion/serialize': 1.1.4 - '@emotion/sheet': 1.2.2 - '@emotion/utils': 1.2.1 + '@esbuild/linux-arm@0.25.12': + optional: true - '@emotion/hash@0.9.1': {} + '@esbuild/linux-arm@0.27.1': + optional: true - '@emotion/memoize@0.8.1': {} + '@esbuild/linux-ia32@0.25.12': + optional: true - '@emotion/react@11.11.4(@types/react@19.0.1)(react@19.0.0)': - dependencies: - '@babel/runtime': 7.24.4 - '@emotion/babel-plugin': 11.11.0 - '@emotion/cache': 11.11.0 - '@emotion/serialize': 1.1.4 - '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@19.0.0) - '@emotion/utils': 1.2.1 - '@emotion/weak-memoize': 0.3.1 - hoist-non-react-statics: 3.3.2 - react: 19.0.0 - optionalDependencies: - '@types/react': 19.0.1 + '@esbuild/linux-ia32@0.27.1': + optional: true - '@emotion/serialize@1.1.4': - dependencies: - '@emotion/hash': 0.9.1 - '@emotion/memoize': 0.8.1 - '@emotion/unitless': 0.8.1 - '@emotion/utils': 1.2.1 - csstype: 3.1.3 + '@esbuild/linux-loong64@0.25.12': + optional: true - '@emotion/sheet@1.2.2': {} + '@esbuild/linux-loong64@0.27.1': + optional: true - '@emotion/unitless@0.8.1': {} + '@esbuild/linux-mips64el@0.25.12': + optional: true - '@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@19.0.0)': - dependencies: - react: 19.0.0 + '@esbuild/linux-mips64el@0.27.1': + optional: true - '@emotion/utils@1.2.1': {} + '@esbuild/linux-ppc64@0.25.12': + optional: true - '@emotion/weak-memoize@0.3.1': {} + '@esbuild/linux-ppc64@0.27.1': + optional: true - '@esbuild/aix-ppc64@0.23.1': + '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/android-arm64@0.23.1': + '@esbuild/linux-riscv64@0.27.1': optional: true - '@esbuild/android-arm@0.23.1': + '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/android-x64@0.23.1': + '@esbuild/linux-s390x@0.27.1': optional: true - '@esbuild/darwin-arm64@0.23.1': + '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/darwin-x64@0.23.1': + '@esbuild/linux-x64@0.27.1': optional: true - '@esbuild/freebsd-arm64@0.23.1': + '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.23.1': + '@esbuild/netbsd-arm64@0.27.1': optional: true - '@esbuild/linux-arm64@0.23.1': + '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/linux-arm@0.23.1': + '@esbuild/netbsd-x64@0.27.1': optional: true - '@esbuild/linux-ia32@0.23.1': + '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/linux-loong64@0.23.1': + '@esbuild/openbsd-arm64@0.27.1': optional: true - '@esbuild/linux-mips64el@0.23.1': + '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.23.1': + '@esbuild/openbsd-x64@0.27.1': optional: true - '@esbuild/linux-riscv64@0.23.1': + '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/linux-s390x@0.23.1': + '@esbuild/openharmony-arm64@0.27.1': optional: true - '@esbuild/linux-x64@0.23.1': + '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.23.1': + '@esbuild/sunos-x64@0.27.1': optional: true - '@esbuild/openbsd-arm64@0.23.1': + '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.23.1': + '@esbuild/win32-arm64@0.27.1': optional: true - '@esbuild/sunos-x64@0.23.1': + '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-arm64@0.23.1': + '@esbuild/win32-ia32@0.27.1': optional: true - '@esbuild/win32-ia32@0.23.1': + '@esbuild/win32-x64@0.25.12': optional: true - '@esbuild/win32-x64@0.23.1': + '@esbuild/win32-x64@0.27.1': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + '@eslint-community/eslint-utils@4.9.0(eslint@8.57.1)': dependencies: - eslint: 8.57.0 + eslint: 8.57.1 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.10.0': {} + '@eslint-community/regexpp@4.12.2': {} '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.4 + debug: 4.4.3 espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/js@8.57.0': {} + '@eslint/js@8.57.1': {} - '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/modal@3.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: body-scroll-lock: 4.0.0-beta.0 focus-trap: 7.5.4 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/scroll-info@2.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/window-info@3.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - '@floating-ui/core@1.6.0': + '@floating-ui/core@1.7.3': dependencies: - '@floating-ui/utils': 0.2.1 + '@floating-ui/utils': 0.2.10 - '@floating-ui/dom@1.6.3': + '@floating-ui/dom@1.7.4': dependencies: - '@floating-ui/core': 1.6.0 - '@floating-ui/utils': 0.2.1 + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 - '@floating-ui/react-dom@2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react-dom@2.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - '@floating-ui/dom': 1.6.3 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@floating-ui/dom': 1.7.4 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - '@floating-ui/react@0.26.28(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react@0.27.16(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@floating-ui/utils': 0.2.8 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - tabbable: 6.2.0 + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@floating-ui/utils': 0.2.10 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + tabbable: 6.3.0 - '@floating-ui/utils@0.2.1': {} + '@floating-ui/utils@0.2.10': {} - '@floating-ui/utils@0.2.8': {} - - '@humanwhocodes/config-array@0.11.14': + '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.4 + debug: 4.4.3 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -3757,129 +3305,171 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@img/sharp-darwin-arm64@0.33.5': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-darwin-arm64@1.0.4': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.0.4': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.0.4': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.0.5': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.0.4': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-linuxmusl-x64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-arm64@0.33.5': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-arm@0.33.5': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linuxmusl-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true - '@img/sharp-wasm32@0.33.5': + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.3.1 + '@emnapi/runtime': 1.7.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-ia32@0.34.5': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-x64@0.34.5': optional: true + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jsdevtools/ono@7.1.3': {} '@juggle/resize-observer@3.4.0': {} - '@monaco-editor/loader@1.4.0(monaco-editor@0.48.0)': + '@monaco-editor/loader@1.7.0': dependencies: - monaco-editor: 0.48.0 state-local: 1.0.7 - '@monaco-editor/react@4.6.0(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - '@monaco-editor/loader': 1.4.0(monaco-editor@0.48.0) - monaco-editor: 0.48.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@monaco-editor/loader': 1.7.0 + monaco-editor: 0.55.1 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - '@mongodb-js/saslprep@1.1.5': + '@mongodb-js/saslprep@1.4.0': dependencies: sparse-bitfield: 3.0.3 - '@next/env@15.1.2': {} + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@next/env@15.5.8': {} - '@next/eslint-plugin-next@15.1.2': + '@next/eslint-plugin-next@15.5.8': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.1.2': + '@next/swc-darwin-arm64@15.5.7': optional: true - '@next/swc-darwin-x64@15.1.2': + '@next/swc-darwin-x64@15.5.7': optional: true - '@next/swc-linux-arm64-gnu@15.1.2': + '@next/swc-linux-arm64-gnu@15.5.7': optional: true - '@next/swc-linux-arm64-musl@15.1.2': + '@next/swc-linux-arm64-musl@15.5.7': optional: true - '@next/swc-linux-x64-gnu@15.1.2': + '@next/swc-linux-x64-gnu@15.5.7': optional: true - '@next/swc-linux-x64-musl@15.1.2': + '@next/swc-linux-x64-musl@15.5.7': optional: true - '@next/swc-win32-arm64-msvc@15.1.2': + '@next/swc-win32-arm64-msvc@15.5.7': optional: true - '@next/swc-win32-x64-msvc@15.1.2': + '@next/swc-win32-x64-msvc@15.5.7': optional: true '@nodelib/fs.scandir@2.1.5': @@ -3892,17 +3482,15 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 + fastq: 1.19.1 '@nolyfill/is-core-module@1.0.39': {} - '@payloadcms/db-mongodb@3.9.0(@aws-sdk/credential-providers@3.556.0)(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(socks@2.8.3)': + '@payloadcms/db-mongodb@3.68.2(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))': dependencies: - http-status: 1.6.2 - mongoose: 8.8.3(@aws-sdk/credential-providers@3.556.0)(socks@2.8.3) - mongoose-aggregate-paginate-v2: 1.1.2 + mongoose: 8.15.1 mongoose-paginate-v2: 1.8.5 - payload: 3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + payload: 3.68.2(graphql@16.12.0)(typescript@5.5.2) prompts: 2.4.2 uuid: 10.0.0 transitivePeerDependencies: @@ -3915,585 +3503,369 @@ snapshots: - socks - supports-color - '@payloadcms/graphql@3.9.0(graphql@16.8.1)(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(typescript@5.5.2)': + '@payloadcms/graphql@3.68.2(graphql@16.12.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(typescript@5.5.2)': dependencies: - graphql: 16.8.1 - graphql-scalars: 1.22.2(graphql@16.8.1) - payload: 3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + graphql: 16.12.0 + graphql-scalars: 1.22.2(graphql@16.12.0) + payload: 3.68.2(graphql@16.12.0)(typescript@5.5.2) pluralize: 8.0.0 ts-essentials: 10.0.3(typescript@5.5.2) - tsx: 4.19.2 + tsx: 4.20.6 transitivePeerDependencies: - typescript - '@payloadcms/next@3.9.0(@types/react@19.0.1)(graphql@16.8.1)(monaco-editor@0.48.0)(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@payloadcms/graphql': 3.9.0(graphql@16.8.1)(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(typescript@5.5.2) - '@payloadcms/translations': 3.9.0 - '@payloadcms/ui': 3.9.0(@types/react@19.0.1)(monaco-editor@0.48.0)(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@payloadcms/graphql': 3.68.2(graphql@16.12.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(typescript@5.5.2) + '@payloadcms/translations': 3.68.2 + '@payloadcms/ui': 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) busboy: 1.6.0 + dequal: 2.0.3 file-type: 19.3.0 - graphql: 16.8.1 - graphql-http: 1.22.1(graphql@16.8.1) + graphql: 16.12.0 + graphql-http: 1.22.4(graphql@16.12.0) graphql-playground-html: 1.6.30 - http-status: 1.6.2 - next: 15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) - path-to-regexp: 6.2.2 - payload: 3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + http-status: 2.1.0 + next: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + path-to-regexp: 6.3.0 + payload: 3.68.2(graphql@16.12.0)(typescript@5.5.2) qs-esm: 7.0.2 - react-diff-viewer-continued: 3.2.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) sass: 1.77.4 - sonner: 1.7.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' - monaco-editor - react - react-dom + - supports-color - typescript - '@payloadcms/richtext-slate@3.9.0(@types/react@19.0.1)(monaco-editor@0.48.0)(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/richtext-slate@3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)': dependencies: - '@payloadcms/translations': 3.9.0 - '@payloadcms/ui': 3.9.0(@types/react@19.0.1)(monaco-editor@0.48.0)(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/translations': 3.68.2 + '@payloadcms/ui': 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) is-hotkey: 0.2.0 - payload: 3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) - react: 19.0.0 + payload: 3.68.2(graphql@16.12.0)(typescript@5.5.2) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) slate: 0.91.4 slate-history: 0.86.0(slate@0.91.4) slate-hyperscript: 0.81.3(slate@0.91.4) - slate-react: 0.92.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(slate@0.91.4) + slate-react: 0.92.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(slate@0.91.4) transitivePeerDependencies: - '@types/react' - monaco-editor - next - - react-dom + - supports-color - typescript - '@payloadcms/translations@3.9.0': + '@payloadcms/translations@3.68.2': dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.9.0(@types/react@19.0.1)(monaco-editor@0.48.0)(next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': - dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@monaco-editor/react': 4.6.0(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@payloadcms/translations': 3.9.0 - body-scroll-lock: 4.0.0-beta.0 + '@payloadcms/ui@3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)': + dependencies: + '@date-fns/tz': 1.2.0 + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) + '@dnd-kit/utilities': 3.2.2(react@19.2.1) + '@faceless-ui/modal': 3.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@faceless-ui/window-info': 3.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@monaco-editor/react': 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@payloadcms/translations': 3.68.2 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) object-to-formdata: 4.5.1 - payload: 3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + payload: 3.68.2(graphql@16.12.0)(typescript@5.5.2) qs-esm: 7.0.2 - react: 19.0.0 - react-datepicker: 7.5.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-dom: 19.0.0(react@19.0.0) - react-image-crop: 10.1.8(react@19.0.0) - react-select: 5.9.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.1 + react-datepicker: 7.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react-dom: 19.2.1(react@19.2.1) + react-image-crop: 10.1.8(react@19.2.1) + react-select: 5.9.0(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) scheduler: 0.25.0 - sonner: 1.7.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + sonner: 1.7.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) ts-essentials: 10.0.3(typescript@5.5.2) - use-context-selector: 2.0.0(react@19.0.0)(scheduler@0.25.0) + use-context-selector: 2.0.0(react@19.2.1)(scheduler@0.25.0) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' - monaco-editor + - supports-color - typescript - '@rtsao/scc@1.1.0': {} + '@pinojs/redact@0.4.0': {} - '@rushstack/eslint-patch@1.10.4': {} + '@rtsao/scc@1.1.0': {} - '@smithy/abort-controller@2.2.0': - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@rushstack/eslint-patch@1.15.0': {} - '@smithy/config-resolver@2.2.0': - dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-config-provider': 2.3.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + '@swc/core-darwin-arm64@1.15.3': optional: true - '@smithy/core@1.4.2': - dependencies: - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + '@swc/core-darwin-x64@1.15.3': optional: true - '@smithy/credential-provider-imds@2.3.0': - dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - tslib: 2.6.2 + '@swc/core-linux-arm-gnueabihf@1.15.3': optional: true - '@smithy/fetch-http-handler@2.5.0': - dependencies: - '@smithy/protocol-http': 3.3.0 - '@smithy/querystring-builder': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/util-base64': 2.3.0 - tslib: 2.6.2 + '@swc/core-linux-arm64-gnu@1.15.3': optional: true - '@smithy/hash-node@2.2.0': - dependencies: - '@smithy/types': 2.12.0 - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + '@swc/core-linux-arm64-musl@1.15.3': optional: true - '@smithy/invalid-dependency@2.2.0': - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@swc/core-linux-x64-gnu@1.15.3': optional: true - '@smithy/is-array-buffer@2.2.0': - dependencies: - tslib: 2.6.2 + '@swc/core-linux-x64-musl@1.15.3': optional: true - '@smithy/middleware-content-length@2.2.0': - dependencies: - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 + '@swc/core-win32-arm64-msvc@1.15.3': optional: true - '@smithy/middleware-endpoint@2.5.1': - dependencies: - '@smithy/middleware-serde': 2.3.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + '@swc/core-win32-ia32-msvc@1.15.3': optional: true - '@smithy/middleware-retry@2.3.1': - dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/service-error-classification': 2.1.5 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - tslib: 2.6.2 - uuid: 9.0.1 + '@swc/core-win32-x64-msvc@1.15.3': optional: true - '@smithy/middleware-serde@2.3.0': + '@swc/core@1.15.3': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@swc/counter': 0.1.3 + '@swc/types': 0.1.25 + optionalDependencies: + '@swc/core-darwin-arm64': 1.15.3 + '@swc/core-darwin-x64': 1.15.3 + '@swc/core-linux-arm-gnueabihf': 1.15.3 + '@swc/core-linux-arm64-gnu': 1.15.3 + '@swc/core-linux-arm64-musl': 1.15.3 + '@swc/core-linux-x64-gnu': 1.15.3 + '@swc/core-linux-x64-musl': 1.15.3 + '@swc/core-win32-arm64-msvc': 1.15.3 + '@swc/core-win32-ia32-msvc': 1.15.3 + '@swc/core-win32-x64-msvc': 1.15.3 - '@smithy/middleware-stack@2.2.0': - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@swc/counter@0.1.3': {} - '@smithy/node-config-provider@2.3.0': + '@swc/helpers@0.5.15': dependencies: - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + tslib: 2.8.1 - '@smithy/node-http-handler@2.5.0': + '@swc/types@0.1.25': dependencies: - '@smithy/abort-controller': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/querystring-builder': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@swc/counter': 0.1.3 - '@smithy/property-provider@2.2.0': - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@tokenizer/token@0.3.0': {} - '@smithy/protocol-http@3.3.0': + '@tybys/wasm-util@0.10.1': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 optional: true - '@smithy/querystring-builder@2.2.0': + '@types/busboy@1.5.4': dependencies: - '@smithy/types': 2.12.0 - '@smithy/util-uri-escape': 2.2.0 - tslib: 2.6.2 - optional: true + '@types/node': 25.0.0 - '@smithy/querystring-parser@2.2.0': - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@types/ejs@3.1.5': {} - '@smithy/service-error-classification@2.1.5': - dependencies: - '@smithy/types': 2.12.0 - optional: true + '@types/is-hotkey@0.1.10': {} - '@smithy/shared-ini-file-loader@2.4.0': - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@types/json-schema@7.0.15': {} - '@smithy/signature-v4@2.3.0': - dependencies: - '@smithy/is-array-buffer': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/util-hex-encoding': 2.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-uri-escape': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - optional: true + '@types/json5@0.0.29': {} - '@smithy/smithy-client@2.5.1': - dependencies: - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-stack': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 - optional: true + '@types/lodash@4.17.21': {} - '@smithy/types@2.12.0': + '@types/node@25.0.0': dependencies: - tslib: 2.6.2 - optional: true + undici-types: 7.16.0 - '@smithy/url-parser@2.2.0': - dependencies: - '@smithy/querystring-parser': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@types/parse-json@4.0.2': {} - '@smithy/util-base64@2.3.0': + '@types/react-dom@19.2.1(@types/react@19.2.1)': dependencies: - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - optional: true + '@types/react': 19.2.1 - '@smithy/util-body-length-browser@2.2.0': + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': dependencies: - tslib: 2.6.2 - optional: true + '@types/react': 19.2.1 - '@smithy/util-body-length-node@2.3.0': + '@types/react@19.2.1': dependencies: - tslib: 2.6.2 - optional: true + csstype: 3.2.3 - '@smithy/util-buffer-from@2.2.0': - dependencies: - '@smithy/is-array-buffer': 2.2.0 - tslib: 2.6.2 + '@types/trusted-types@2.0.7': optional: true - '@smithy/util-config-provider@2.3.0': + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@11.0.5': dependencies: - tslib: 2.6.2 - optional: true + '@types/webidl-conversions': 7.0.3 - '@smithy/util-defaults-mode-browser@2.2.1': + '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1)(typescript@5.5.2)': dependencies: - '@smithy/property-provider': 2.2.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - bowser: 2.11.0 - tslib: 2.6.2 - optional: true + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.49.0(eslint@8.57.1)(typescript@5.5.2) + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/type-utils': 8.49.0(eslint@8.57.1)(typescript@5.5.2) + '@typescript-eslint/utils': 8.49.0(eslint@8.57.1)(typescript@5.5.2) + '@typescript-eslint/visitor-keys': 8.49.0 + eslint: 8.57.1 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.5.2) + typescript: 5.5.2 + transitivePeerDependencies: + - supports-color - '@smithy/util-defaults-mode-node@2.3.1': + '@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.5.2)': dependencies: - '@smithy/config-resolver': 2.2.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.5.2) + '@typescript-eslint/visitor-keys': 8.49.0 + debug: 4.4.3 + eslint: 8.57.1 + typescript: 5.5.2 + transitivePeerDependencies: + - supports-color - '@smithy/util-endpoints@1.2.0': + '@typescript-eslint/project-service@8.49.0(typescript@5.5.2)': dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.5.2) + '@typescript-eslint/types': 8.49.0 + debug: 4.4.3 + typescript: 5.5.2 + transitivePeerDependencies: + - supports-color - '@smithy/util-hex-encoding@2.2.0': + '@typescript-eslint/scope-manager@8.49.0': dependencies: - tslib: 2.6.2 - optional: true + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/visitor-keys': 8.49.0 - '@smithy/util-middleware@2.2.0': + '@typescript-eslint/tsconfig-utils@8.49.0(typescript@5.5.2)': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + typescript: 5.5.2 - '@smithy/util-retry@2.2.0': + '@typescript-eslint/type-utils@8.49.0(eslint@8.57.1)(typescript@5.5.2)': dependencies: - '@smithy/service-error-classification': 2.1.5 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - optional: true + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.5.2) + '@typescript-eslint/utils': 8.49.0(eslint@8.57.1)(typescript@5.5.2) + debug: 4.4.3 + eslint: 8.57.1 + ts-api-utils: 2.1.0(typescript@5.5.2) + typescript: 5.5.2 + transitivePeerDependencies: + - supports-color - '@smithy/util-stream@2.2.0': + '@typescript-eslint/types@8.49.0': {} + + '@typescript-eslint/typescript-estree@8.49.0(typescript@5.5.2)': dependencies: - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/types': 2.12.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-hex-encoding': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - optional: true + '@typescript-eslint/project-service': 8.49.0(typescript@5.5.2) + '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.5.2) + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/visitor-keys': 8.49.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.5.2) + typescript: 5.5.2 + transitivePeerDependencies: + - supports-color - '@smithy/util-uri-escape@2.2.0': + '@typescript-eslint/utils@8.49.0(eslint@8.57.1)(typescript@5.5.2)': dependencies: - tslib: 2.6.2 - optional: true + '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.5.2) + eslint: 8.57.1 + typescript: 5.5.2 + transitivePeerDependencies: + - supports-color - '@smithy/util-utf8@2.3.0': + '@typescript-eslint/visitor-keys@8.49.0': dependencies: - '@smithy/util-buffer-from': 2.2.0 - tslib: 2.6.2 - optional: true + '@typescript-eslint/types': 8.49.0 + eslint-visitor-keys: 4.2.1 - '@swc/core-darwin-arm64@1.10.1': - optional: true + '@ungap/structured-clone@1.3.0': {} - '@swc/core-darwin-x64@1.10.1': + '@unrs/resolver-binding-android-arm-eabi@1.11.1': optional: true - '@swc/core-linux-arm-gnueabihf@1.10.1': + '@unrs/resolver-binding-android-arm64@1.11.1': optional: true - '@swc/core-linux-arm64-gnu@1.10.1': + '@unrs/resolver-binding-darwin-arm64@1.11.1': optional: true - '@swc/core-linux-arm64-musl@1.10.1': + '@unrs/resolver-binding-darwin-x64@1.11.1': optional: true - '@swc/core-linux-x64-gnu@1.10.1': + '@unrs/resolver-binding-freebsd-x64@1.11.1': optional: true - '@swc/core-linux-x64-musl@1.10.1': + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': optional: true - '@swc/core-win32-arm64-msvc@1.10.1': + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': optional: true - '@swc/core-win32-ia32-msvc@1.10.1': + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': optional: true - '@swc/core-win32-x64-msvc@1.10.1': + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': optional: true - '@swc/core@1.10.1(@swc/helpers@0.5.15)': - dependencies: - '@swc/counter': 0.1.3 - '@swc/types': 0.1.17 - optionalDependencies: - '@swc/core-darwin-arm64': 1.10.1 - '@swc/core-darwin-x64': 1.10.1 - '@swc/core-linux-arm-gnueabihf': 1.10.1 - '@swc/core-linux-arm64-gnu': 1.10.1 - '@swc/core-linux-arm64-musl': 1.10.1 - '@swc/core-linux-x64-gnu': 1.10.1 - '@swc/core-linux-x64-musl': 1.10.1 - '@swc/core-win32-arm64-msvc': 1.10.1 - '@swc/core-win32-ia32-msvc': 1.10.1 - '@swc/core-win32-x64-msvc': 1.10.1 - '@swc/helpers': 0.5.15 - - '@swc/counter@0.1.3': {} - - '@swc/helpers@0.5.15': - dependencies: - tslib: 2.8.1 - - '@swc/types@0.1.17': - dependencies: - '@swc/counter': 0.1.3 - - '@tokenizer/token@0.3.0': {} - - '@types/busboy@1.5.4': - dependencies: - '@types/node': 20.12.7 - - '@types/ejs@3.1.5': {} - - '@types/is-hotkey@0.1.10': {} - - '@types/json-schema@7.0.15': {} - - '@types/json5@0.0.29': {} - - '@types/lodash@4.17.0': {} - - '@types/lodash@4.17.13': {} - - '@types/node@20.12.7': - dependencies: - undici-types: 5.26.5 - - '@types/parse-json@4.0.2': {} - - '@types/react-dom@19.0.1': - dependencies: - '@types/react': 19.0.1 - - '@types/react-transition-group@4.4.10': - dependencies: - '@types/react': 19.0.1 - - '@types/react@19.0.1': - dependencies: - csstype: 3.1.3 - - '@types/semver@7.5.8': {} - - '@types/webidl-conversions@7.0.3': {} - - '@types/whatwg-url@11.0.5': - dependencies: - '@types/webidl-conversions': 7.0.3 + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true - '@typescript-eslint/eslint-plugin@6.6.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2)': - dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.6.0(eslint@8.57.0)(typescript@5.5.2) - '@typescript-eslint/scope-manager': 6.6.0 - '@typescript-eslint/type-utils': 6.6.0(eslint@8.57.0)(typescript@5.5.2) - '@typescript-eslint/utils': 6.6.0(eslint@8.57.0)(typescript@5.5.2) - '@typescript-eslint/visitor-keys': 6.6.0 - debug: 4.3.4 - eslint: 8.57.0 - graphemer: 1.4.0 - ignore: 5.3.1 - natural-compare: 1.4.0 - semver: 7.6.0 - ts-api-utils: 1.3.0(typescript@5.5.2) - optionalDependencies: - typescript: 5.5.2 - transitivePeerDependencies: - - supports-color + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true - '@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2)': - dependencies: - '@typescript-eslint/scope-manager': 6.6.0 - '@typescript-eslint/types': 6.6.0 - '@typescript-eslint/typescript-estree': 6.6.0(typescript@5.5.2) - '@typescript-eslint/visitor-keys': 6.6.0 - debug: 4.3.4 - eslint: 8.57.0 - optionalDependencies: - typescript: 5.5.2 - transitivePeerDependencies: - - supports-color + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true - '@typescript-eslint/scope-manager@6.6.0': - dependencies: - '@typescript-eslint/types': 6.6.0 - '@typescript-eslint/visitor-keys': 6.6.0 + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true - '@typescript-eslint/type-utils@6.6.0(eslint@8.57.0)(typescript@5.5.2)': - dependencies: - '@typescript-eslint/typescript-estree': 6.6.0(typescript@5.5.2) - '@typescript-eslint/utils': 6.6.0(eslint@8.57.0)(typescript@5.5.2) - debug: 4.3.4 - eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.5.2) - optionalDependencies: - typescript: 5.5.2 - transitivePeerDependencies: - - supports-color + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true - '@typescript-eslint/types@6.6.0': {} + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true - '@typescript-eslint/typescript-estree@6.6.0(typescript@5.5.2)': + '@unrs/resolver-binding-wasm32-wasi@1.11.1': dependencies: - '@typescript-eslint/types': 6.6.0 - '@typescript-eslint/visitor-keys': 6.6.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.6.0 - ts-api-utils: 1.3.0(typescript@5.5.2) - optionalDependencies: - typescript: 5.5.2 - transitivePeerDependencies: - - supports-color + '@napi-rs/wasm-runtime': 0.2.12 + optional: true - '@typescript-eslint/utils@6.6.0(eslint@8.57.0)(typescript@5.5.2)': - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 6.6.0 - '@typescript-eslint/types': 6.6.0 - '@typescript-eslint/typescript-estree': 6.6.0(typescript@5.5.2) - eslint: 8.57.0 - semver: 7.6.0 - transitivePeerDependencies: - - supports-color - - typescript + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true - '@typescript-eslint/visitor-keys@6.6.0': - dependencies: - '@typescript-eslint/types': 6.6.0 - eslint-visitor-keys: 3.4.3 + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true - '@ungap/structured-clone@1.2.0': {} + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true - acorn-jsx@5.3.2(acorn@8.11.3): + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: - acorn: 8.11.3 + acorn: 8.15.0 - acorn@8.11.3: {} + acorn@8.15.0: {} ajv@6.12.6: dependencies: @@ -4505,16 +3877,12 @@ snapshots: ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.0.3 + fast-uri: 3.1.0 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 ansi-regex@5.0.1: {} - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 - ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -4528,100 +3896,92 @@ snapshots: aria-query@5.3.2: {} - array-buffer-byte-length@1.0.1: + array-buffer-byte-length@1.0.2: dependencies: - call-bind: 1.0.7 - is-array-buffer: 3.0.4 + call-bound: 1.0.4 + is-array-buffer: 3.0.5 - array-includes@3.1.8: + array-includes@3.1.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 - is-string: 1.0.7 - - array-union@2.1.0: {} + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 array.prototype.findlast@1.2.5: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-shim-unscopables: 1.0.2 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 - array.prototype.findlastindex@1.2.5: + array.prototype.findlastindex@1.2.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-shim-unscopables: 1.0.2 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 - array.prototype.flat@1.3.2: + array.prototype.flat@1.3.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 - array.prototype.flatmap@1.3.2: + array.prototype.flatmap@1.3.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 array.prototype.tosorted@1.1.4: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-errors: 1.3.0 - es-shim-unscopables: 1.0.2 - - arraybuffer.prototype.slice@1.0.3: - dependencies: - array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - is-array-buffer: 3.0.4 - is-shared-array-buffer: 1.0.3 + es-shim-unscopables: 1.1.0 arraybuffer.prototype.slice@1.0.4: dependencies: - array-buffer-byte-length: 1.0.1 + array-buffer-byte-length: 1.0.2 call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.6 + es-abstract: 1.24.0 es-errors: 1.3.0 - get-intrinsic: 1.2.6 - is-array-buffer: 3.0.4 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 ast-types-flow@0.0.8: {} + async-function@1.0.0: {} + atomic-sleep@1.0.0: {} available-typed-arrays@1.0.7: dependencies: - possible-typed-array-names: 1.0.0 + possible-typed-array-names: 1.1.0 - axe-core@4.10.2: {} + axe-core@4.11.0: {} axobject-query@4.1.0: {} babel-plugin-macros@3.1.0: dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.28.4 cosmiconfig: 7.1.0 - resolve: 1.22.8 + resolve: 1.22.11 balanced-match@1.0.2: {} @@ -4629,60 +3989,47 @@ snapshots: body-scroll-lock@4.0.0-beta.0: {} - bowser@2.11.0: - optional: true - - brace-expansion@1.1.11: + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - braces@3.0.2: + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: dependencies: - fill-range: 7.0.1 + fill-range: 7.1.1 bson-objectid@2.0.4: {} - bson@6.10.1: {} + bson@6.10.4: {} busboy@1.6.0: dependencies: streamsearch: 1.1.0 - call-bind-apply-helpers@1.0.1: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.7: + call-bind-apply-helpers@1.0.2: dependencies: - es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - set-function-length: 1.2.2 call-bind@1.0.8: dependencies: - call-bind-apply-helpers: 1.0.1 - es-define-property: 1.0.0 - get-intrinsic: 1.2.6 + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 set-function-length: 1.2.2 - call-bound@1.0.3: + call-bound@1.0.4: dependencies: - call-bind-apply-helpers: 1.0.1 - get-intrinsic: 1.2.6 + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 callsites@3.1.0: {} - caniuse-lite@1.0.30001612: {} - - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 + caniuse-lite@1.0.30001760: {} chalk@4.1.2: dependencies: @@ -4694,7 +4041,7 @@ snapshots: chokidar@3.6.0: dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -4703,38 +4050,18 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - ci-info@4.0.0: {} - - classnames@2.5.1: {} + ci-info@4.3.1: {} client-only@0.0.1: {} clsx@2.1.1: {} - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - color-convert@2.0.1: dependencies: color-name: 1.1.4 - color-name@1.1.3: {} - color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - colorette@2.0.20: {} commander@2.20.3: {} @@ -4745,25 +4072,25 @@ snapshots: console-table-printer@2.12.1: dependencies: - simple-wcswidth: 1.0.1 + simple-wcswidth: 1.1.2 convert-source-map@1.9.0: {} cosmiconfig@7.1.0: dependencies: '@types/parse-json': 4.0.2 - import-fresh: 3.3.0 + import-fresh: 3.3.1 parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.2 - croner@9.0.0: {} + croner@9.1.0: {} cross-env@7.0.3: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 - cross-spawn@7.0.3: + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -4773,27 +4100,27 @@ snapshots: cssfilter@0.0.10: {} - csstype@3.1.3: {} + csstype@3.2.3: {} damerau-levenshtein@1.0.8: {} - data-view-buffer@1.0.1: + data-view-buffer@1.0.2: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 - data-view-byte-length@1.0.1: + data-view-byte-length@1.0.2: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 - data-view-byte-offset@1.0.0: + data-view-byte-offset@1.0.1: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 dataloader@2.2.3: {} @@ -4807,11 +4134,7 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.3.4: - dependencies: - ms: 2.1.2 - - debug@4.4.0: + debug@4.4.3: dependencies: ms: 2.1.3 @@ -4821,9 +4144,9 @@ snapshots: define-data-property@1.1.4: dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 - gopd: 1.0.1 + gopd: 1.2.0 define-properties@1.2.1: dependencies: @@ -4833,15 +4156,9 @@ snapshots: dequal@2.0.3: {} - detect-libc@2.0.3: + detect-libc@2.1.2: optional: true - diff@5.2.0: {} - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - direction@1.0.4: {} doctrine@2.1.0: @@ -4854,97 +4171,48 @@ snapshots: dom-helpers@5.2.1: dependencies: - '@babel/runtime': 7.24.4 - csstype: 3.1.3 + '@babel/runtime': 7.28.4 + csstype: 3.2.3 + + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 dunder-proto@1.0.1: dependencies: - call-bind-apply-helpers: 1.0.1 + call-bind-apply-helpers: 1.0.2 es-errors: 1.3.0 gopd: 1.2.0 emoji-regex@9.2.2: {} - end-of-stream@1.4.4: + end-of-stream@1.4.5: dependencies: once: 1.4.0 - enhanced-resolve@5.17.1: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.2.1 - - error-ex@1.3.2: + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 - es-abstract@1.23.3: - dependencies: - array-buffer-byte-length: 1.0.1 - arraybuffer.prototype.slice: 1.0.3 - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - data-view-buffer: 1.0.1 - data-view-byte-length: 1.0.1 - data-view-byte-offset: 1.0.0 - es-define-property: 1.0.0 - es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-set-tostringtag: 2.0.3 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.6 - get-intrinsic: 1.2.4 - get-symbol-description: 1.0.2 - globalthis: 1.0.3 - gopd: 1.0.1 - has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - hasown: 2.0.2 - internal-slot: 1.0.7 - is-array-buffer: 3.0.4 - is-callable: 1.2.7 - is-data-view: 1.0.1 - is-negative-zero: 2.0.3 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.3 - is-string: 1.0.7 - is-typed-array: 1.1.13 - is-weakref: 1.0.2 - object-inspect: 1.13.1 - object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 - safe-array-concat: 1.1.2 - safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.9 - string.prototype.trimend: 1.0.8 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.2 - typed-array-byte-length: 1.0.1 - typed-array-byte-offset: 1.0.2 - typed-array-length: 1.0.6 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.15 - - es-abstract@1.23.6: + es-abstract@1.24.0: dependencies: - array-buffer-byte-length: 1.0.1 + array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 available-typed-arrays: 1.0.7 call-bind: 1.0.8 - call-bound: 1.0.3 - data-view-buffer: 1.0.1 - data-view-byte-length: 1.0.1 - data-view-byte-offset: 1.0.0 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-set-tostringtag: 2.0.3 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 es-to-primitive: 1.3.0 - function.prototype.name: 1.1.7 - get-intrinsic: 1.2.6 - get-symbol-description: 1.0.2 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 globalthis: 1.0.4 gopd: 1.2.0 has-property-descriptors: 1.0.2 @@ -4952,128 +4220,154 @@ snapshots: has-symbols: 1.1.0 hasown: 2.0.2 internal-slot: 1.1.0 - is-array-buffer: 3.0.4 + is-array-buffer: 3.0.5 is-callable: 1.2.7 is-data-view: 1.0.2 is-negative-zero: 2.0.3 is-regex: 1.2.1 - is-shared-array-buffer: 1.0.3 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 is-string: 1.1.1 - is-typed-array: 1.1.13 - is-weakref: 1.1.0 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 math-intrinsics: 1.1.0 - object-inspect: 1.13.3 + object-inspect: 1.13.4 object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.3 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 string.prototype.trim: 1.2.10 string.prototype.trimend: 1.0.9 string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.2 - typed-array-byte-length: 1.0.1 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 typed-array-byte-offset: 1.0.4 typed-array-length: 1.0.7 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.18 - - es-define-property@1.0.0: - dependencies: - get-intrinsic: 1.2.4 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 es-define-property@1.0.1: {} es-errors@1.3.0: {} - es-iterator-helpers@1.2.0: + es-iterator-helpers@1.2.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 + es-set-tostringtag: 2.1.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 globalthis: 1.0.4 - gopd: 1.0.1 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - iterator.prototype: 1.1.4 - safe-array-concat: 1.1.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 - es-object-atoms@1.0.0: + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 - es-set-tostringtag@2.0.3: + es-set-tostringtag@2.1.0: dependencies: - get-intrinsic: 1.2.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 hasown: 2.0.2 - es-shim-unscopables@1.0.2: + es-shim-unscopables@1.1.0: dependencies: hasown: 2.0.2 - es-to-primitive@1.2.1: - dependencies: - is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 - es-to-primitive@1.3.0: dependencies: is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 + is-date-object: 1.1.0 + is-symbol: 1.1.1 - esbuild@0.23.1: + esbuild@0.25.12: optionalDependencies: - '@esbuild/aix-ppc64': 0.23.1 - '@esbuild/android-arm': 0.23.1 - '@esbuild/android-arm64': 0.23.1 - '@esbuild/android-x64': 0.23.1 - '@esbuild/darwin-arm64': 0.23.1 - '@esbuild/darwin-x64': 0.23.1 - '@esbuild/freebsd-arm64': 0.23.1 - '@esbuild/freebsd-x64': 0.23.1 - '@esbuild/linux-arm': 0.23.1 - '@esbuild/linux-arm64': 0.23.1 - '@esbuild/linux-ia32': 0.23.1 - '@esbuild/linux-loong64': 0.23.1 - '@esbuild/linux-mips64el': 0.23.1 - '@esbuild/linux-ppc64': 0.23.1 - '@esbuild/linux-riscv64': 0.23.1 - '@esbuild/linux-s390x': 0.23.1 - '@esbuild/linux-x64': 0.23.1 - '@esbuild/netbsd-x64': 0.23.1 - '@esbuild/openbsd-arm64': 0.23.1 - '@esbuild/openbsd-x64': 0.23.1 - '@esbuild/sunos-x64': 0.23.1 - '@esbuild/win32-arm64': 0.23.1 - '@esbuild/win32-ia32': 0.23.1 - '@esbuild/win32-x64': 0.23.1 - - escape-string-regexp@1.0.5: {} + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + esbuild@0.27.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.1 + '@esbuild/android-arm': 0.27.1 + '@esbuild/android-arm64': 0.27.1 + '@esbuild/android-x64': 0.27.1 + '@esbuild/darwin-arm64': 0.27.1 + '@esbuild/darwin-x64': 0.27.1 + '@esbuild/freebsd-arm64': 0.27.1 + '@esbuild/freebsd-x64': 0.27.1 + '@esbuild/linux-arm': 0.27.1 + '@esbuild/linux-arm64': 0.27.1 + '@esbuild/linux-ia32': 0.27.1 + '@esbuild/linux-loong64': 0.27.1 + '@esbuild/linux-mips64el': 0.27.1 + '@esbuild/linux-ppc64': 0.27.1 + '@esbuild/linux-riscv64': 0.27.1 + '@esbuild/linux-s390x': 0.27.1 + '@esbuild/linux-x64': 0.27.1 + '@esbuild/netbsd-arm64': 0.27.1 + '@esbuild/netbsd-x64': 0.27.1 + '@esbuild/openbsd-arm64': 0.27.1 + '@esbuild/openbsd-x64': 0.27.1 + '@esbuild/openharmony-arm64': 0.27.1 + '@esbuild/sunos-x64': 0.27.1 + '@esbuild/win32-arm64': 0.27.1 + '@esbuild/win32-ia32': 0.27.1 + '@esbuild/win32-x64': 0.27.1 escape-string-regexp@4.0.0: {} - eslint-config-next@15.1.2(eslint@8.57.0)(typescript@5.5.2): + eslint-config-next@15.5.8(eslint@8.57.1)(typescript@5.5.2): dependencies: - '@next/eslint-plugin-next': 15.1.2 - '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/eslint-plugin': 6.6.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2) - '@typescript-eslint/parser': 6.6.0(eslint@8.57.0)(typescript@5.5.2) - eslint: 8.57.0 + '@next/eslint-plugin-next': 15.5.8 + '@rushstack/eslint-patch': 1.15.0 + '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1)(typescript@5.5.2) + '@typescript-eslint/parser': 8.49.0(eslint@8.57.1)(typescript@5.5.2) + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) - eslint-plugin-react: 7.37.2(eslint@8.57.0) - eslint-plugin-react-hooks: 5.1.0(eslint@8.57.0) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) + eslint-plugin-react: 7.37.5(eslint@8.57.1) + eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) optionalDependencies: typescript: 5.5.2 transitivePeerDependencies: @@ -5084,110 +4378,109 @@ snapshots: eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 - is-core-module: 2.13.1 - resolve: 1.22.8 + is-core-module: 2.16.1 + resolve: 1.22.11 transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.0 - enhanced-resolve: 5.17.1 - eslint: 8.57.0 - fast-glob: 3.3.2 - get-tsconfig: 4.8.1 - is-bun-module: 1.3.0 - is-glob: 4.0.3 - stable-hash: 0.0.4 + debug: 4.4.3 + eslint: 8.57.1 + get-tsconfig: 4.13.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.15 + unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 6.6.0(eslint@8.57.0)(typescript@5.5.2) - eslint: 8.57.0 + '@typescript-eslint/parser': 8.49.0(eslint@8.57.1)(typescript@5.5.2) + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 - array-includes: 3.1.8 - array.prototype.findlastindex: 1.2.5 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.0 + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.6.0(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) hasown: 2.0.2 - is-core-module: 2.16.0 + is-core-module: 2.16.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 object.groupby: 1.0.3 - object.values: 1.2.0 + object.values: 1.2.1 semver: 6.3.1 - string.prototype.trimend: 1.0.8 + string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 6.6.0(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/parser': 8.49.0(eslint@8.57.1)(typescript@5.5.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0): + eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1): dependencies: aria-query: 5.3.2 - array-includes: 3.1.8 - array.prototype.flatmap: 1.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 ast-types-flow: 0.0.8 - axe-core: 4.10.2 + axe-core: 4.11.0 axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 8.57.0 + eslint: 8.57.1 hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 minimatch: 3.1.2 object.fromentries: 2.0.8 - safe-regex-test: 1.0.3 + safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@5.1.0(eslint@8.57.0): + eslint-plugin-react-hooks@5.2.0(eslint@8.57.1): dependencies: - eslint: 8.57.0 + eslint: 8.57.1 - eslint-plugin-react@7.37.2(eslint@8.57.0): + eslint-plugin-react@7.37.5(eslint@8.57.1): dependencies: - array-includes: 3.1.8 + array-includes: 3.1.9 array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.2 + array.prototype.flatmap: 1.3.3 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.2.0 - eslint: 8.57.0 + es-iterator-helpers: 1.2.1 + eslint: 8.57.1 estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 - object.entries: 1.1.8 + object.entries: 1.1.9 object.fromentries: 2.0.8 - object.values: 1.2.0 + object.values: 1.2.1 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 - string.prototype.matchall: 4.0.11 + string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 eslint-scope@7.2.2: @@ -5197,26 +4490,28 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint@8.57.0: + eslint-visitor-keys@4.2.1: {} + + eslint@8.57.1: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.10.0 + '@eslint-community/eslint-utils': 4.9.0(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.2 '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 + '@ungap/structured-clone': 1.3.0 ajv: 6.12.6 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4 + cross-spawn: 7.0.6 + debug: 4.4.3 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 @@ -5224,17 +4519,17 @@ snapshots: glob-parent: 6.0.2 globals: 13.24.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 - js-yaml: 4.1.0 + js-yaml: 4.1.1 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: @@ -5242,11 +4537,11 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 3.4.3 - esquery@1.5.0: + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -5268,38 +4563,23 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 - - fast-glob@3.3.2: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.8 fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} - fast-redact@3.5.0: {} - fast-safe-stringify@2.1.1: {} - fast-uri@3.0.3: {} - - fast-xml-parser@4.2.5: - dependencies: - strnum: 1.0.5 - optional: true + fast-uri@3.1.0: {} - fastq@1.17.1: + fastq@1.19.1: dependencies: - reusify: 1.0.4 + reusify: 1.1.0 - fdir@6.4.2(picomatch@4.0.2): + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: - picomatch: 4.0.2 + picomatch: 4.0.3 file-entry-cache@6.0.1: dependencies: @@ -5308,10 +4588,10 @@ snapshots: file-type@19.3.0: dependencies: strtok3: 8.1.0 - token-types: 6.0.0 - uint8array-extras: 1.4.0 + token-types: 6.1.1 + uint8array-extras: 1.5.0 - fill-range@7.0.1: + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -5324,17 +4604,17 @@ snapshots: flat-cache@3.2.0: dependencies: - flatted: 3.3.1 + flatted: 3.3.3 keyv: 4.5.4 rimraf: 3.0.2 - flatted@3.3.1: {} + flatted@3.3.3: {} focus-trap@7.5.4: dependencies: - tabbable: 6.2.0 + tabbable: 6.3.0 - for-each@0.3.3: + for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -5345,16 +4625,10 @@ snapshots: function-bind@1.1.2: {} - function.prototype.name@1.1.6: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - functions-have-names: 1.2.3 - - function.prototype.name@1.1.7: + function.prototype.name@1.1.8: dependencies: call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 functions-have-names: 1.2.3 hasown: 2.0.2 @@ -5362,32 +4636,35 @@ snapshots: functions-have-names@1.2.3: {} - get-intrinsic@1.2.4: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - hasown: 2.0.2 + generator-function@2.0.1: {} - get-intrinsic@1.2.6: + get-intrinsic@1.3.0: dependencies: - call-bind-apply-helpers: 1.0.1 - dunder-proto: 1.0.1 + call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 function-bind: 1.1.2 + get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 hasown: 2.0.2 math-intrinsics: 1.1.0 - get-symbol-description@1.0.2: + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 get-tsconfig@4.8.1: dependencies: @@ -5414,72 +4691,47 @@ snapshots: dependencies: type-fest: 0.20.2 - globalthis@1.0.3: - dependencies: - define-properties: 1.2.1 - globalthis@1.0.4: dependencies: define-properties: 1.2.1 - gopd: 1.0.1 - - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.1 - merge2: 1.4.1 - slash: 3.0.0 - - gopd@1.0.1: - dependencies: - get-intrinsic: 1.2.4 + gopd: 1.2.0 gopd@1.2.0: {} - graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - graphql-http@1.22.1(graphql@16.8.1): + graphql-http@1.22.4(graphql@16.12.0): dependencies: - graphql: 16.8.1 + graphql: 16.12.0 graphql-playground-html@1.6.30: dependencies: xss: 1.0.15 - graphql-scalars@1.22.2(graphql@16.8.1): + graphql-scalars@1.22.2(graphql@16.12.0): dependencies: - graphql: 16.8.1 - tslib: 2.6.2 - - graphql@16.8.1: {} + graphql: 16.12.0 + tslib: 2.8.1 - has-bigints@1.0.2: {} + graphql@16.12.0: {} - has-flag@3.0.0: {} + has-bigints@1.1.0: {} has-flag@4.0.0: {} has-property-descriptors@1.0.2: dependencies: - es-define-property: 1.0.0 - - has-proto@1.0.3: {} + es-define-property: 1.0.1 has-proto@1.2.0: dependencies: dunder-proto: 1.0.1 - has-symbols@1.0.3: {} - has-symbols@1.1.0: {} has-tostringtag@1.0.2: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 hasown@2.0.2: dependencies: @@ -5491,21 +4743,21 @@ snapshots: dependencies: react-is: 16.13.1 - http-status@1.6.2: {} + http-status@2.1.0: {} ieee754@1.2.1: {} - ignore@5.3.1: {} + ignore@5.3.2: {} - image-size@1.1.1: - dependencies: - queue: 6.0.2 + ignore@7.0.5: {} + + image-size@2.0.2: {} immer@9.0.21: {} - immutable@4.3.5: {} + immutable@4.3.7: {} - import-fresh@3.3.0: + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 @@ -5519,104 +4771,79 @@ snapshots: inherits@2.0.4: {} - internal-slot@1.0.7: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.0.6 - internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.2 side-channel: 1.1.0 - ip-address@9.0.5: - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 - optional: true + ipaddr.js@2.2.0: {} - is-array-buffer@3.0.4: + is-array-buffer@3.0.5: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 is-arrayish@0.2.1: {} - is-arrayish@0.3.2: - optional: true - - is-async-function@2.0.0: + is-async-function@2.1.1: dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 has-tostringtag: 1.0.2 - - is-bigint@1.0.4: - dependencies: - has-bigints: 1.0.2 + safe-regex-test: 1.1.0 is-bigint@1.1.0: dependencies: - has-bigints: 1.0.2 + has-bigints: 1.1.0 is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 - is-boolean-object@1.1.2: - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - - is-boolean-object@1.2.1: + is-boolean-object@1.2.2: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-tostringtag: 1.0.2 is-buffer@1.1.6: {} - is-bun-module@1.3.0: + is-bun-module@2.0.0: dependencies: - semver: 7.6.3 + semver: 7.7.3 is-callable@1.2.7: {} - is-core-module@2.13.1: - dependencies: - hasown: 2.0.2 - - is-core-module@2.16.0: + is-core-module@2.16.1: dependencies: hasown: 2.0.2 - is-data-view@1.0.1: - dependencies: - is-typed-array: 1.1.13 - is-data-view@1.0.2: dependencies: - call-bound: 1.0.3 - get-intrinsic: 1.2.6 - is-typed-array: 1.1.13 - - is-date-object@1.0.5: - dependencies: - has-tostringtag: 1.0.2 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 is-date-object@1.1.0: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-tostringtag: 1.0.2 is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 - is-generator-function@1.0.10: + is-generator-function@1.1.2: dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 is-glob@4.0.3: dependencies: @@ -5630,13 +4857,9 @@ snapshots: is-negative-zero@2.0.3: {} - is-number-object@1.0.7: - dependencies: - has-tostringtag: 1.0.2 - is-number-object@1.1.1: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-tostringtag: 1.0.2 is-number@7.0.0: {} @@ -5645,77 +4868,56 @@ snapshots: is-plain-object@5.0.0: {} - is-regex@1.1.4: - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - is-regex@1.2.1: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 gopd: 1.2.0 has-tostringtag: 1.0.2 hasown: 2.0.2 is-set@2.0.3: {} - is-shared-array-buffer@1.0.3: - dependencies: - call-bind: 1.0.7 - - is-string@1.0.7: + is-shared-array-buffer@1.0.4: dependencies: - has-tostringtag: 1.0.2 + call-bound: 1.0.4 is-string@1.1.1: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-tostringtag: 1.0.2 - is-symbol@1.0.4: - dependencies: - has-symbols: 1.0.3 - is-symbol@1.1.1: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-symbols: 1.1.0 safe-regex-test: 1.1.0 - is-typed-array@1.1.13: - dependencies: - which-typed-array: 1.1.15 - is-typed-array@1.1.15: dependencies: - which-typed-array: 1.1.18 + which-typed-array: 1.1.19 is-weakmap@2.0.2: {} - is-weakref@1.0.2: - dependencies: - call-bind: 1.0.7 - - is-weakref@1.1.0: + is-weakref@1.1.1: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 - is-weakset@2.0.3: + is-weakset@2.0.4: dependencies: - call-bind: 1.0.8 - get-intrinsic: 1.2.6 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 isarray@2.0.5: {} isexe@2.0.0: {} - iterator.prototype@1.1.4: + iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 - es-object-atoms: 1.0.0 - get-intrinsic: 1.2.6 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 has-symbols: 1.1.0 - reflect.getprototypeof: 1.0.9 set-function-name: 2.0.2 jose@5.9.6: {} @@ -5724,12 +4926,11 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@4.1.0: + js-yaml@4.1.1: dependencies: argparse: 2.0.1 - jsbn@1.1.0: - optional: true + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -5737,15 +4938,15 @@ snapshots: json-schema-to-typescript@15.0.3: dependencies: - '@apidevtools/json-schema-ref-parser': 11.7.3 + '@apidevtools/json-schema-ref-parser': 11.9.3 '@types/json-schema': 7.0.15 - '@types/lodash': 4.17.13 + '@types/lodash': 4.17.21 is-glob: 4.0.3 - js-yaml: 4.1.0 + js-yaml: 4.1.1 lodash: 4.17.21 minimist: 1.2.8 - prettier: 3.4.2 - tinyglobby: 0.2.10 + prettier: 3.7.4 + tinyglobby: 0.2.15 json-schema-traverse@0.4.1: {} @@ -5759,10 +4960,10 @@ snapshots: jsx-ast-utils@3.3.5: dependencies: - array-includes: 3.1.8 - array.prototype.flat: 1.3.2 - object.assign: 4.1.5 - object.values: 1.2.0 + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 kareem@2.6.3: {} @@ -5772,11 +4973,11 @@ snapshots: kleur@3.0.3: {} - language-subtag-registry@0.3.22: {} + language-subtag-registry@0.3.23: {} language-tags@1.0.9: dependencies: - language-subtag-registry: 0.3.22 + language-subtag-registry: 0.3.23 levn@0.4.1: dependencies: @@ -5797,9 +4998,7 @@ snapshots: dependencies: js-tokens: 4.0.0 - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 + marked@14.0.0: {} math-intrinsics@1.1.0: {} @@ -5815,42 +5014,44 @@ snapshots: merge2@1.4.1: {} - micromatch@4.0.5: + micromatch@4.0.8: dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 minimatch@3.1.2: dependencies: - brace-expansion: 1.1.11 + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 minimist@1.2.8: {} - monaco-editor@0.48.0: {} + monaco-editor@0.55.1: + dependencies: + dompurify: 3.2.7 + marked: 14.0.0 - mongodb-connection-string-url@3.0.1: + mongodb-connection-string-url@3.0.2: dependencies: '@types/whatwg-url': 11.0.5 - whatwg-url: 13.0.0 + whatwg-url: 14.2.0 - mongodb@6.10.0(@aws-sdk/credential-providers@3.556.0)(socks@2.8.3): + mongodb@6.16.0: dependencies: - '@mongodb-js/saslprep': 1.1.5 - bson: 6.10.1 - mongodb-connection-string-url: 3.0.1 - optionalDependencies: - '@aws-sdk/credential-providers': 3.556.0 - socks: 2.8.3 - - mongoose-aggregate-paginate-v2@1.1.2: {} + '@mongodb-js/saslprep': 1.4.0 + bson: 6.10.4 + mongodb-connection-string-url: 3.0.2 mongoose-paginate-v2@1.8.5: {} - mongoose@8.8.3(@aws-sdk/credential-providers@3.556.0)(socks@2.8.3): + mongoose@8.15.1: dependencies: - bson: 6.10.1 + bson: 6.10.4 kareem: 2.6.3 - mongodb: 6.10.0(@aws-sdk/credential-providers@3.556.0)(socks@2.8.3) + mongodb: 6.16.0 mpath: 0.9.0 mquery: 5.0.0 ms: 2.1.3 @@ -5869,40 +5070,38 @@ snapshots: mquery@5.0.0: dependencies: - debug: 4.3.4 + debug: 4.4.3 transitivePeerDependencies: - supports-color - ms@2.1.2: {} - ms@2.1.3: {} - nanoid@3.3.7: {} + nanoid@3.3.11: {} + + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} - next@15.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): + next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.1.2 - '@swc/counter': 0.1.3 + '@next/env': 15.5.8 '@swc/helpers': 0.5.15 - busboy: 1.6.0 - caniuse-lite: 1.0.30001612 + caniuse-lite: 1.0.30001760 postcss: 8.4.31 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + styled-jsx: 5.1.6(react@19.2.1) optionalDependencies: - '@next/swc-darwin-arm64': 15.1.2 - '@next/swc-darwin-x64': 15.1.2 - '@next/swc-linux-arm64-gnu': 15.1.2 - '@next/swc-linux-arm64-musl': 15.1.2 - '@next/swc-linux-x64-gnu': 15.1.2 - '@next/swc-linux-x64-musl': 15.1.2 - '@next/swc-win32-arm64-msvc': 15.1.2 - '@next/swc-win32-x64-msvc': 15.1.2 + '@next/swc-darwin-arm64': 15.5.7 + '@next/swc-darwin-x64': 15.5.7 + '@next/swc-linux-arm64-gnu': 15.5.7 + '@next/swc-linux-arm64-musl': 15.5.7 + '@next/swc-linux-x64-gnu': 15.5.7 + '@next/swc-linux-x64-musl': 15.5.7 + '@next/swc-win32-arm64-msvc': 15.5.7 + '@next/swc-win32-x64-msvc': 15.5.7 sass: 1.77.4 - sharp: 0.33.5 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -5911,45 +5110,47 @@ snapshots: object-assign@4.1.1: {} - object-inspect@1.13.1: {} - - object-inspect@1.13.3: {} + object-inspect@1.13.4: {} object-keys@1.1.1: {} object-to-formdata@4.5.1: {} - object.assign@4.1.5: + object.assign@4.1.7: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - has-symbols: 1.0.3 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 object-keys: 1.1.1 - object.entries@1.1.8: + object.entries@1.1.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 object.fromentries@2.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 object.groupby@1.0.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 - object.values@1.2.0: + object.values@1.2.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 on-exit-leak-free@2.1.2: {} @@ -5957,14 +5158,20 @@ snapshots: dependencies: wrappy: 1.0.2 - optionator@0.9.3: + optionator@0.9.4: dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 p-limit@3.1.0: dependencies: @@ -5980,8 +5187,8 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.24.2 - error-ex: 1.3.2 + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -5993,61 +5200,62 @@ snapshots: path-parse@1.0.7: {} - path-to-regexp@6.2.2: {} + path-to-regexp@6.3.0: {} path-type@4.0.0: {} - payload@3.9.0(graphql@16.8.1)(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2): + payload@3.68.2(graphql@16.12.0)(typescript@5.5.2): dependencies: - '@monaco-editor/react': 4.6.0(monaco-editor@0.48.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@next/env': 15.1.2 - '@payloadcms/translations': 3.9.0 + '@next/env': 15.5.8 + '@payloadcms/translations': 3.68.2 '@types/busboy': 1.5.4 ajv: 8.17.1 bson-objectid: 2.0.4 - ci-info: 4.0.0 + busboy: 1.6.0 + ci-info: 4.3.1 console-table-printer: 2.12.1 - croner: 9.0.0 + croner: 9.1.0 dataloader: 2.2.3 deepmerge: 4.3.1 file-type: 19.3.0 get-tsconfig: 4.8.1 - graphql: 16.8.1 - http-status: 1.6.2 - image-size: 1.1.1 + graphql: 16.12.0 + http-status: 2.1.0 + image-size: 2.0.2 + ipaddr.js: 2.2.0 jose: 5.9.6 json-schema-to-typescript: 15.0.3 minimist: 1.2.8 - pino: 9.5.0 - pino-pretty: 13.0.0 + path-to-regexp: 6.3.0 + pino: 9.14.0 + pino-pretty: 13.1.2 pluralize: 8.0.0 + qs-esm: 7.0.2 sanitize-filename: 1.6.3 scmp: 2.1.0 ts-essentials: 10.0.3(typescript@5.5.2) - tsx: 4.19.2 + tsx: 4.20.3 + undici: 7.10.0 uuid: 10.0.0 - ws: 8.16.0 + ws: 8.18.3 transitivePeerDependencies: - bufferutil - - monaco-editor - - react - - react-dom - typescript - utf-8-validate - peek-readable@5.3.1: {} + peek-readable@5.4.2: {} - picocolors@1.0.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} - picomatch@4.0.2: {} + picomatch@4.0.3: {} pino-abstract-transport@2.0.0: dependencies: split2: 4.2.0 - pino-pretty@13.0.0: + pino-pretty@13.1.2: dependencies: colorette: 2.0.20 dateformat: 4.6.3 @@ -6058,42 +5266,42 @@ snapshots: minimist: 1.2.8 on-exit-leak-free: 2.1.2 pino-abstract-transport: 2.0.0 - pump: 3.0.0 - secure-json-parse: 2.7.0 + pump: 3.0.3 + secure-json-parse: 4.1.0 sonic-boom: 4.2.0 - strip-json-comments: 3.1.1 + strip-json-comments: 5.0.3 pino-std-serializers@7.0.0: {} - pino@9.5.0: + pino@9.14.0: dependencies: + '@pinojs/redact': 0.4.0 atomic-sleep: 1.0.0 - fast-redact: 3.5.0 on-exit-leak-free: 2.1.2 pino-abstract-transport: 2.0.0 pino-std-serializers: 7.0.0 - process-warning: 4.0.0 + process-warning: 5.0.0 quick-format-unescaped: 4.0.4 real-require: 0.2.0 - safe-stable-stringify: 2.4.3 + safe-stable-stringify: 2.5.0 sonic-boom: 4.2.0 thread-stream: 3.1.0 pluralize@8.0.0: {} - possible-typed-array-names@1.0.0: {} + possible-typed-array-names@1.1.0: {} postcss@8.4.31: dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.2.0 + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 prelude-ls@1.2.1: {} - prettier@3.4.2: {} + prettier@3.7.4: {} - process-warning@4.0.0: {} + process-warning@5.0.0: {} prompts@2.4.2: dependencies: @@ -6106,9 +5314,9 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 - pump@3.0.0: + pump@3.0.3: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 punycode@2.3.1: {} @@ -6117,72 +5325,58 @@ snapshots: queue-microtask@1.2.3: {} - queue@6.0.2: - dependencies: - inherits: 2.0.4 - quick-format-unescaped@4.0.4: {} - react-datepicker@7.5.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-datepicker@7.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - '@floating-ui/react': 0.26.28(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react': 0.27.16(react-dom@19.2.1(react@19.2.1))(react@19.2.1) clsx: 2.1.1 date-fns: 3.6.0 - prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - - react-diff-viewer-continued@3.2.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@emotion/css': 11.11.2 - classnames: 2.5.1 - diff: 5.2.0 - memoize-one: 6.0.0 - prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - react-dom@19.0.0(react@19.0.0): + react-dom@19.2.1(react@19.2.1): dependencies: - react: 19.0.0 - scheduler: 0.25.0 + react: 19.2.1 + scheduler: 0.27.0 - react-hook-form@7.51.3(react@19.0.0): + react-hook-form@7.68.0(react@19.2.1): dependencies: - react: 19.0.0 + react: 19.2.1 - react-image-crop@10.1.8(react@19.0.0): + react-image-crop@10.1.8(react@19.2.1): dependencies: - react: 19.0.0 + react: 19.2.1 react-is@16.13.1: {} - react-select@5.9.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-select@5.9.0(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - '@babel/runtime': 7.24.4 - '@emotion/cache': 11.11.0 - '@emotion/react': 11.11.4(@types/react@19.0.1)(react@19.0.0) - '@floating-ui/dom': 1.6.3 - '@types/react-transition-group': 4.4.10 + '@babel/runtime': 7.28.4 + '@emotion/cache': 11.14.0 + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.1) + '@floating-ui/dom': 1.7.4 + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - use-isomorphic-layout-effect: 1.2.0(@types/react@19.0.1)(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.1)(react@19.2.1) transitivePeerDependencies: - '@types/react' + - supports-color - react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-transition-group@4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.28.4 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - react@19.0.0: {} + react@19.2.1: {} readdirp@3.6.0: dependencies: @@ -6190,31 +5384,24 @@ snapshots: real-require@0.2.0: {} - reflect.getprototypeof@1.0.9: + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - dunder-proto: 1.0.1 - es-abstract: 1.23.6 + es-abstract: 1.24.0 es-errors: 1.3.0 - get-intrinsic: 1.2.6 - gopd: 1.2.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 which-builtin-type: 1.2.1 - regenerator-runtime@0.14.1: {} - - regexp.prototype.flags@1.5.2: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-errors: 1.3.0 - set-function-name: 2.0.2 - - regexp.prototype.flags@1.5.3: + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 set-function-name: 2.0.2 require-from-string@2.0.2: {} @@ -6223,19 +5410,19 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve@1.22.8: + resolve@1.22.11: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 resolve@2.0.0-next.5: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - reusify@1.0.4: {} + reusify@1.1.0: {} rimraf@3.0.2: dependencies: @@ -6245,34 +5432,26 @@ snapshots: dependencies: queue-microtask: 1.2.3 - safe-array-concat@1.1.2: - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - isarray: 2.0.5 - safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 - call-bound: 1.0.3 - get-intrinsic: 1.2.6 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 has-symbols: 1.1.0 isarray: 2.0.5 - safe-regex-test@1.0.3: + safe-push-apply@1.0.0: dependencies: - call-bind: 1.0.7 es-errors: 1.3.0 - is-regex: 1.1.4 + isarray: 2.0.5 safe-regex-test@1.1.0: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 is-regex: 1.2.1 - safe-stable-stringify@2.4.3: {} + safe-stable-stringify@2.5.0: {} sanitize-filename@1.6.3: dependencies: @@ -6281,34 +5460,32 @@ snapshots: sass@1.77.4: dependencies: chokidar: 3.6.0 - immutable: 4.3.5 - source-map-js: 1.2.0 + immutable: 4.3.7 + source-map-js: 1.2.1 scheduler@0.25.0: {} + scheduler@0.27.0: {} + scmp@2.1.0: {} scroll-into-view-if-needed@2.2.31: dependencies: compute-scroll-into-view: 1.0.20 - secure-json-parse@2.7.0: {} + secure-json-parse@4.1.0: {} semver@6.3.1: {} - semver@7.6.0: - dependencies: - lru-cache: 6.0.0 - - semver@7.6.3: {} + semver@7.7.3: {} set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 has-property-descriptors: 1.0.2 set-function-name@2.0.2: @@ -6318,31 +5495,42 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 - sharp@0.33.5: + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.3 - semver: 7.6.3 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -6354,51 +5542,37 @@ snapshots: side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 - object-inspect: 1.13.3 + object-inspect: 1.13.4 side-channel-map@1.0.1: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 - get-intrinsic: 1.2.6 - object-inspect: 1.13.3 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 side-channel-weakmap@1.0.2: dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 - get-intrinsic: 1.2.6 - object-inspect: 1.13.3 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 side-channel-map: 1.0.1 - side-channel@1.0.6: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.1 - side-channel@1.1.0: dependencies: es-errors: 1.3.0 - object-inspect: 1.13.3 + object-inspect: 1.13.4 side-channel-list: 1.0.0 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 sift@17.1.3: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - - simple-wcswidth@1.0.1: {} + simple-wcswidth@1.1.2: {} sisteransi@1.0.5: {} - slash@3.0.0: {} - slate-history@0.86.0(slate@0.91.4): dependencies: is-plain-object: 5.0.0 @@ -6409,17 +5583,17 @@ snapshots: is-plain-object: 5.0.0 slate: 0.91.4 - slate-react@0.92.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(slate@0.91.4): + slate-react@0.92.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(slate@0.91.4): dependencies: '@juggle/resize-observer': 3.4.0 '@types/is-hotkey': 0.1.10 - '@types/lodash': 4.17.0 + '@types/lodash': 4.17.21 direction: 1.0.4 is-hotkey: 0.1.8 is-plain-object: 5.0.0 lodash: 4.17.21 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) scroll-into-view-if-needed: 2.2.31 slate: 0.91.4 tiny-invariant: 1.0.6 @@ -6430,25 +5604,16 @@ snapshots: is-plain-object: 5.0.0 tiny-warning: 1.0.3 - smart-buffer@4.2.0: - optional: true - - socks@2.8.3: - dependencies: - ip-address: 9.0.5 - smart-buffer: 4.2.0 - optional: true - sonic-boom@4.2.0: dependencies: atomic-sleep: 1.0.0 - sonner@1.7.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + sonner@1.7.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - source-map-js@1.2.0: {} + source-map-js@1.2.1: {} source-map@0.5.7: {} @@ -6458,76 +5623,66 @@ snapshots: split2@4.2.0: {} - sprintf-js@1.1.3: - optional: true - - stable-hash@0.0.4: {} + stable-hash@0.0.5: {} state-local@1.0.7: {} + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + streamsearch@1.1.0: {} string.prototype.includes@2.0.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 - string.prototype.matchall@4.0.11: + string.prototype.matchall@4.0.12: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 es-errors: 1.3.0 - es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - regexp.prototype.flags: 1.5.2 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 set-function-name: 2.0.2 - side-channel: 1.0.6 + side-channel: 1.1.0 string.prototype.repeat@1.0.0: dependencies: define-properties: 1.2.1 - es-abstract: 1.23.3 + es-abstract: 1.24.0 string.prototype.trim@1.2.10: dependencies: call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.23.6 - es-object-atoms: 1.0.0 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 has-property-descriptors: 1.0.2 - string.prototype.trim@1.2.9: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 - - string.prototype.trimend@1.0.8: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - string.prototype.trimend@1.0.9: dependencies: call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 strip-ansi@6.0.1: dependencies: @@ -6537,34 +5692,27 @@ snapshots: strip-json-comments@3.1.1: {} - strnum@1.0.5: - optional: true + strip-json-comments@5.0.3: {} strtok3@8.1.0: dependencies: '@tokenizer/token': 0.3.0 - peek-readable: 5.3.1 + peek-readable: 5.4.2 - styled-jsx@5.1.6(react@19.0.0): + styled-jsx@5.1.6(react@19.2.1): dependencies: client-only: 0.0.1 - react: 19.0.0 + react: 19.2.1 stylis@4.2.0: {} - supports-color@5.5.0: - dependencies: - has-flag: 3.0.0 - supports-color@7.2.0: dependencies: has-flag: 4.0.0 supports-preserve-symlinks-flag@1.0.0: {} - tabbable@6.2.0: {} - - tapable@2.2.1: {} + tabbable@6.3.0: {} text-table@0.2.0: {} @@ -6576,31 +5724,30 @@ snapshots: tiny-warning@1.0.3: {} - tinyglobby@0.2.10: + tinyglobby@0.2.15: dependencies: - fdir: 6.4.2(picomatch@4.0.2) - picomatch: 4.0.2 - - to-fast-properties@2.0.0: {} + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - token-types@6.0.0: + token-types@6.1.1: dependencies: + '@borewit/text-codec': 0.1.1 '@tokenizer/token': 0.3.0 ieee754: 1.2.1 - tr46@4.1.1: + tr46@5.1.1: dependencies: punycode: 2.3.1 truncate-utf8-bytes@1.0.2: dependencies: - utf8-byte-length: 1.0.4 + utf8-byte-length: 1.0.5 - ts-api-utils@1.3.0(typescript@5.5.2): + ts-api-utils@2.1.0(typescript@5.5.2): dependencies: typescript: 5.5.2 @@ -6615,172 +5762,171 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tslib@1.14.1: - optional: true - - tslib@2.6.2: {} - tslib@2.8.1: {} - tsx@4.19.2: + tsx@4.20.3: dependencies: - esbuild: 0.23.1 + esbuild: 0.25.12 get-tsconfig: 4.8.1 optionalDependencies: fsevents: 2.3.3 + tsx@4.20.6: + dependencies: + esbuild: 0.25.12 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + + tsx@4.21.0: + dependencies: + esbuild: 0.27.1 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 type-fest@0.20.2: {} - typed-array-buffer@1.0.2: + typed-array-buffer@1.0.3: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-typed-array: 1.1.13 - - typed-array-byte-length@1.0.1: - dependencies: - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 + is-typed-array: 1.1.15 - typed-array-byte-offset@1.0.2: + typed-array-byte-length@1.0.3: dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 typed-array-byte-offset@1.0.4: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.8 - for-each: 0.3.3 + for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.9 - - typed-array-length@1.0.6: - dependencies: - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 - possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.10 typed-array-length@1.0.7: dependencies: call-bind: 1.0.8 - for-each: 0.3.3 + for-each: 0.3.5 gopd: 1.2.0 - is-typed-array: 1.1.13 - possible-typed-array-names: 1.0.0 - reflect.getprototypeof: 1.0.9 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 typescript@5.5.2: {} - uint8array-extras@1.4.0: {} + uint8array-extras@1.5.0: {} - unbox-primitive@1.0.2: + unbox-primitive@1.1.0: dependencies: - call-bind: 1.0.7 - has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@7.16.0: {} + + undici@7.10.0: {} - undici-types@5.26.5: {} + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 uri-js@4.4.1: dependencies: punycode: 2.3.1 - use-context-selector@2.0.0(react@19.0.0)(scheduler@0.25.0): + use-context-selector@2.0.0(react@19.2.1)(scheduler@0.25.0): dependencies: - react: 19.0.0 + react: 19.2.1 scheduler: 0.25.0 - use-isomorphic-layout-effect@1.2.0(@types/react@19.0.1)(react@19.0.0): + use-isomorphic-layout-effect@1.2.1(@types/react@19.2.1)(react@19.2.1): dependencies: - react: 19.0.0 + react: 19.2.1 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - utf8-byte-length@1.0.4: {} + utf8-byte-length@1.0.5: {} uuid@10.0.0: {} - uuid@9.0.1: - optional: true - webidl-conversions@7.0.0: {} - whatwg-url@13.0.0: + whatwg-url@14.2.0: dependencies: - tr46: 4.1.1 + tr46: 5.1.1 webidl-conversions: 7.0.0 - which-boxed-primitive@1.0.2: - dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 - which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 - is-boolean-object: 1.2.1 + is-boolean-object: 1.2.2 is-number-object: 1.1.1 is-string: 1.1.1 is-symbol: 1.1.1 which-builtin-type@1.2.1: dependencies: - call-bound: 1.0.3 - function.prototype.name: 1.1.6 + call-bound: 1.0.4 + function.prototype.name: 1.1.8 has-tostringtag: 1.0.2 - is-async-function: 2.0.0 + is-async-function: 2.1.1 is-date-object: 1.1.0 is-finalizationregistry: 1.1.1 - is-generator-function: 1.0.10 + is-generator-function: 1.1.2 is-regex: 1.2.1 - is-weakref: 1.0.2 + is-weakref: 1.1.1 isarray: 2.0.5 which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.18 + which-typed-array: 1.1.19 which-collection@1.0.2: dependencies: is-map: 2.0.3 is-set: 2.0.3 is-weakmap: 2.0.2 - is-weakset: 2.0.3 - - which-typed-array@1.1.15: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.2 + is-weakset: 2.0.4 - which-typed-array@1.1.18: + which-typed-array@1.1.19: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.8 - call-bound: 1.0.3 - for-each: 0.3.3 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 gopd: 1.2.0 has-tostringtag: 1.0.2 @@ -6788,17 +5934,17 @@ snapshots: dependencies: isexe: 2.0.0 + word-wrap@1.2.5: {} + wrappy@1.0.2: {} - ws@8.16.0: {} + ws@8.18.3: {} xss@1.0.15: dependencies: commander: 2.20.3 cssfilter: 0.0.10 - yallist@4.0.0: {} - yaml@1.10.2: {} yocto-queue@0.1.0: {} diff --git a/examples/custom-components/package.json b/examples/custom-components/package.json index 51e72d438fb..9a458fa5246 100644 --- a/examples/custom-components/package.json +++ b/examples/custom-components/package.json @@ -25,7 +25,7 @@ "dotenv": "^8.2.0", "graphql": "^16.9.0", "install": "^0.13.0", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1" diff --git a/examples/custom-components/pnpm-lock.yaml b/examples/custom-components/pnpm-lock.yaml index 539018590c5..e0891970115 100644 --- a/examples/custom-components/pnpm-lock.yaml +++ b/examples/custom-components/pnpm-lock.yaml @@ -10,19 +10,19 @@ importers: dependencies: '@payloadcms/db-mongodb': specifier: latest - version: 3.18.0(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)) + version: 3.18.0(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)) '@payloadcms/graphql': specifier: latest - version: 3.18.0(graphql@16.10.0)(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(typescript@5.5.2) + version: 3.18.0(graphql@16.10.0)(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(typescript@5.5.2) '@payloadcms/next': specifier: latest - version: 3.18.0(@types/react@19.0.7)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.18.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@payloadcms/richtext-lexical': specifier: latest - version: 3.18.0(bvirogffrpuzy2e4p57bv2watq) + version: 3.18.0(9d0cbd55753b1430a277687619c49ac8) '@payloadcms/ui': specifier: latest - version: 3.18.0(@types/react@19.0.7)(monaco-editor@0.52.2)(next@15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.18.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -36,17 +36,17 @@ importers: specifier: ^0.13.0 version: 0.13.0 next: - specifier: ^15.0.0 - version: 15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + specifier: ^15.4.9 + version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest - version: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) react: - specifier: ^19.0.0 - version: 19.0.0 + specifier: ^19.2.1 + version: 19.2.2 react-dom: - specifier: ^19.0.0 - version: 19.0.0(react@19.0.0) + specifier: ^19.2.1 + version: 19.2.2(react@19.2.2) devDependencies: '@swc/core': specifier: ^1.6.13 @@ -55,11 +55,11 @@ importers: specifier: ^3.1.5 version: 3.1.5 '@types/react': - specifier: ^19.0.0 - version: 19.0.7 + specifier: 19.2.1 + version: 19.2.1 '@types/react-dom': - specifier: ^19.0.0 - version: 19.0.3(@types/react@19.0.7) + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -142,8 +142,8 @@ packages: peerDependencies: react: '>=16.8.0' - '@emnapi/runtime@1.3.1': - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -360,8 +360,8 @@ packages: '@faceless-ui/scroll-info@2.0.0-beta.0': resolution: {integrity: sha512-pUBhQP8vduA7rVndNsjhaCcds1BykA/Q4iV23JWijU6ZFL/M3Fm9P3ypDS+0VVxolqemNhw8S3FXPwZGgjH4Rw==} peerDependencies: - react: ^19.0.0-rc-f994737d14-20240522 - react-dom: ^19.0.0-rc-f994737d14-20240522 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 '@faceless-ui/window-info@3.0.0-beta.0': resolution: {integrity: sha512-Qs8xRA+fl4sU2aFVe9xawxfi5TVZ9VTPuhdQpx9aSv7U5a2F0AXwT61lJfnaJ9Flm8tOcxzq67p8cVZsXNCVeQ==} @@ -403,107 +403,139 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -621,53 +653,56 @@ packages: '@next/env@15.1.6': resolution: {integrity: sha512-d9AFQVPEYNr+aqokIiPLNK/MTyt3DWa/dpKveiAaVccUadFbhFEvY6FXYX2LJO2Hv7PHnLBu2oWwB4uBuHjr/w==} + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + '@next/eslint-plugin-next@15.1.6': resolution: {integrity: sha512-+slMxhTgILUntZDGNgsKEYHUvpn72WP1YTlkmEhS51vnVd7S9jEEy0n9YAMcI21vUG4akTw9voWH02lrClt/yw==} - '@next/swc-darwin-arm64@15.1.6': - resolution: {integrity: sha512-u7lg4Mpl9qWpKgy6NzEkz/w0/keEHtOybmIl0ykgItBxEM5mYotS5PmqTpo+Rhg8FiOiWgwr8USxmKQkqLBCrw==} + '@next/swc-darwin-arm64@15.5.7': + resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.1.6': - resolution: {integrity: sha512-x1jGpbHbZoZ69nRuogGL2MYPLqohlhnT9OCU6E6QFewwup+z+M6r8oU47BTeJcWsF2sdBahp5cKiAcDbwwK/lg==} + '@next/swc-darwin-x64@15.5.7': + resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.1.6': - resolution: {integrity: sha512-jar9sFw0XewXsBzPf9runGzoivajeWJUc/JkfbLTC4it9EhU8v7tCRLH7l5Y1ReTMN6zKJO0kKAGqDk8YSO2bg==} + '@next/swc-linux-arm64-gnu@15.5.7': + resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.1.6': - resolution: {integrity: sha512-+n3u//bfsrIaZch4cgOJ3tXCTbSxz0s6brJtU3SzLOvkJlPQMJ+eHVRi6qM2kKKKLuMY+tcau8XD9CJ1OjeSQQ==} + '@next/swc-linux-arm64-musl@15.5.7': + resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.1.6': - resolution: {integrity: sha512-SpuDEXixM3PycniL4iVCLyUyvcl6Lt0mtv3am08sucskpG0tYkW1KlRhTgj4LI5ehyxriVVcfdoxuuP8csi3kQ==} + '@next/swc-linux-x64-gnu@15.5.7': + resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.1.6': - resolution: {integrity: sha512-L4druWmdFSZIIRhF+G60API5sFB7suTbDRhYWSjiw0RbE+15igQvE2g2+S973pMGvwN3guw7cJUjA/TmbPWTHQ==} + '@next/swc-linux-x64-musl@15.5.7': + resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.1.6': - resolution: {integrity: sha512-s8w6EeqNmi6gdvM19tqKKWbCyOBvXFbndkGHl+c9YrzsLARRdCHsD9S1fMj8gsXm9v8vhC8s3N8rjuC/XrtkEg==} + '@next/swc-win32-arm64-msvc@15.5.7': + resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.1.6': - resolution: {integrity: sha512-6xomMuu54FAFxttYr5PJbEfu96godcxBTRk1OhAvJq0/EnmFU/Ybiax30Snis4vdWZ9LGpf7Roy5fSs7v/5ROQ==} + '@next/swc-win32-x64-msvc@15.5.7': + resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -871,18 +906,18 @@ packages: '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/react-dom@19.0.3': - resolution: {integrity: sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} peerDependencies: - '@types/react': ^19.0.0 + '@types/react': ^19.2.0 '@types/react-transition-group@4.4.12': resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} peerDependencies: '@types/react': '*' - '@types/react@19.0.7': - resolution: {integrity: sha512-MoFsEJKkAtZCrC1r6CM8U22GzhG7u2Wir8ons/aCKH6MBdD1ibV24zOSSkdZVUKqN5i396zG5VKLYZ3yaUZdLA==} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1141,13 +1176,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -1255,8 +1283,8 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} devlop@1.1.0: @@ -1709,9 +1737,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-async-function@2.1.0: resolution: {integrity: sha512-GExz9MtyhlZyXYLxzlJRj5WUCE661zhDa1Yna52CN57AJsymh+DvXXjyveSioqSRdxvUrdKdvqB1b5cVKsNpWQ==} engines: {node: '>= 0.4'} @@ -2120,13 +2145,13 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.1.6: - resolution: {integrity: sha512-Hch4wzbaX0vKQtalpXvUiw5sYivBy4cm5rzUKrBnUB/y436LGrvOUqYvlSeNVCWFO/770gDlltR9gqZH62ct4Q==} + next@15.5.8: + resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 + '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 @@ -2330,8 +2355,8 @@ packages: react-datepicker@7.6.0: resolution: {integrity: sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==} peerDependencies: - react: 19.0.0 - react-dom: 19.0.0 + react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc react-diff-viewer-continued@3.2.6: resolution: {integrity: sha512-GrzyqQnjIMoej+jMjWvtVSsQqhXgzEGqpXlJ2dAGfOk7Q26qcm8Gu6xtI430PBUyZsERe8BJSQf+7VZZo8IBNQ==} @@ -2340,10 +2365,10 @@ packages: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom@19.0.0: - resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + react-dom@19.2.2: + resolution: {integrity: sha512-fhyD2BLrew6qYf4NNtHff1rLXvzR25rq49p+FeqByOazc6TcSi2n8EYulo5C1PbH+1uBW++5S1SG7FcUU6mlDg==} peerDependencies: - react: ^19.0.0 + react: ^19.2.2 react-error-boundary@3.1.4: resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} @@ -2367,8 +2392,8 @@ packages: react-select@5.9.0: resolution: {integrity: sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw==} peerDependencies: - react: 19.0.0 - react-dom: 19.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-transition-group@4.4.5: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} @@ -2376,8 +2401,8 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' - react@19.0.0: - resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} + react@19.2.2: + resolution: {integrity: sha512-BdOGOY8OKRBcgoDkwqA8Q5XvOIhoNx/Sh6BnGJlet2Abt0X5BK0BDrqGyQgLhAVjD2nAg5f6o01u/OPUhG022Q==} engines: {node: '>=0.10.0'} readdirp@3.6.0: @@ -2458,6 +2483,9 @@ packages: scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + scmp@2.1.0: resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} @@ -2473,6 +2501,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2485,8 +2518,8 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -2516,9 +2549,6 @@ packages: sift@17.1.3: resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - simple-wcswidth@1.0.1: resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==} @@ -2897,32 +2927,32 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@dnd-kit/accessibility@3.1.1(react@19.0.0)': + '@dnd-kit/accessibility@3.1.1(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@dnd-kit/accessibility': 3.1.1(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tslib: 2.8.1 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.0.0)': + '@dnd-kit/utilities@3.2.2(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 - '@emnapi/runtime@1.3.1': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -2965,19 +2995,19 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.0.7)(react@19.0.0)': + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.2)': dependencies: '@babel/runtime': 7.26.0 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.0.0) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.2) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.7 + '@types/react': 19.2.1 transitivePeerDependencies: - supports-color @@ -2993,9 +3023,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.0.0)': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 '@emotion/utils@1.4.2': {} @@ -3096,23 +3126,23 @@ snapshots: '@eslint/js@8.57.1': {} - '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: body-scroll-lock: 4.0.0-beta.0 focus-trap: 7.5.4 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) - '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@floating-ui/core@1.6.9': dependencies: @@ -3123,18 +3153,18 @@ snapshots: '@floating-ui/core': 1.6.9 '@floating-ui/utils': 0.2.9 - '@floating-ui/react-dom@2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react-dom@2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@floating-ui/dom': 1.6.13 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@floating-ui/react@0.27.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react@0.27.3(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react-dom': 2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@floating-ui/utils': 0.2.9 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tabbable: 6.2.0 '@floating-ui/utils@0.2.9': {} @@ -3151,79 +3181,101 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@img/sharp-darwin-arm64@0.33.5': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.0.4': + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.0.4': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.0.4': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.0.5': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.0.4': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-linux-arm64@0.33.5': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - '@img/sharp-linux-arm@0.33.5': + '@img/sharp-linux-arm@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-wasm32@0.33.5': + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.3.1 + '@emnapi/runtime': 1.7.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-ia32@0.34.5': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-x64@0.34.5': optional: true '@jridgewell/gen-mapping@0.3.8': @@ -3259,7 +3311,7 @@ snapshots: lexical: 0.21.0 prismjs: 1.29.0 - '@lexical/devtools-core@0.21.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@lexical/devtools-core@0.21.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@lexical/html': 0.21.0 '@lexical/link': 0.21.0 @@ -3267,8 +3319,8 @@ snapshots: '@lexical/table': 0.21.0 '@lexical/utils': 0.21.0 lexical: 0.21.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@lexical/dragon@0.21.0': dependencies: @@ -3334,11 +3386,11 @@ snapshots: '@lexical/utils': 0.21.0 lexical: 0.21.0 - '@lexical/react@0.21.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(yjs@13.6.23)': + '@lexical/react@0.21.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.23)': dependencies: '@lexical/clipboard': 0.21.0 '@lexical/code': 0.21.0 - '@lexical/devtools-core': 0.21.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@lexical/devtools-core': 0.21.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@lexical/dragon': 0.21.0 '@lexical/hashtag': 0.21.0 '@lexical/history': 0.21.0 @@ -3355,9 +3407,9 @@ snapshots: '@lexical/utils': 0.21.0 '@lexical/yjs': 0.21.0(yjs@13.6.23) lexical: 0.21.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-error-boundary: 3.1.4(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 3.1.4(react@19.2.2) transitivePeerDependencies: - yjs @@ -3401,12 +3453,12 @@ snapshots: monaco-editor: 0.52.2 state-local: 1.0.7 - '@monaco-editor/react@4.6.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@monaco-editor/react@4.6.0(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@monaco-editor/loader': 1.4.0(monaco-editor@0.52.2) monaco-editor: 0.52.2 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@mongodb-js/saslprep@1.1.9': dependencies: @@ -3414,32 +3466,34 @@ snapshots: '@next/env@15.1.6': {} + '@next/env@15.5.8': {} + '@next/eslint-plugin-next@15.1.6': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.1.6': + '@next/swc-darwin-arm64@15.5.7': optional: true - '@next/swc-darwin-x64@15.1.6': + '@next/swc-darwin-x64@15.5.7': optional: true - '@next/swc-linux-arm64-gnu@15.1.6': + '@next/swc-linux-arm64-gnu@15.5.7': optional: true - '@next/swc-linux-arm64-musl@15.1.6': + '@next/swc-linux-arm64-musl@15.5.7': optional: true - '@next/swc-linux-x64-gnu@15.1.6': + '@next/swc-linux-x64-gnu@15.5.7': optional: true - '@next/swc-linux-x64-musl@15.1.6': + '@next/swc-linux-x64-musl@15.5.7': optional: true - '@next/swc-win32-arm64-msvc@15.1.6': + '@next/swc-win32-arm64-msvc@15.5.7': optional: true - '@next/swc-win32-x64-msvc@15.1.6': + '@next/swc-win32-x64-msvc@15.5.7': optional: true '@nodelib/fs.scandir@2.1.5': @@ -3456,12 +3510,12 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@payloadcms/db-mongodb@3.18.0(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))': + '@payloadcms/db-mongodb@3.18.0(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))': dependencies: mongoose: 8.9.5 mongoose-aggregate-paginate-v2: 1.1.2 mongoose-paginate-v2: 1.8.5 - payload: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + payload: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) prompts: 2.4.2 uuid: 10.0.0 transitivePeerDependencies: @@ -3474,36 +3528,36 @@ snapshots: - socks - supports-color - '@payloadcms/graphql@3.18.0(graphql@16.10.0)(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(typescript@5.5.2)': + '@payloadcms/graphql@3.18.0(graphql@16.10.0)(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(typescript@5.5.2)': dependencies: graphql: 16.10.0 graphql-scalars: 1.22.2(graphql@16.10.0) - payload: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + payload: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) pluralize: 8.0.0 ts-essentials: 10.0.3(typescript@5.5.2) tsx: 4.19.2 transitivePeerDependencies: - typescript - '@payloadcms/next@3.18.0(@types/react@19.0.7)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/next@3.18.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@payloadcms/graphql': 3.18.0(graphql@16.10.0)(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(typescript@5.5.2) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@payloadcms/graphql': 3.18.0(graphql@16.10.0)(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(typescript@5.5.2) '@payloadcms/translations': 3.18.0 - '@payloadcms/ui': 3.18.0(@types/react@19.0.7)(monaco-editor@0.52.2)(next@15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/ui': 3.18.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) busboy: 1.6.0 file-type: 19.3.0 graphql: 16.10.0 graphql-http: 1.22.4(graphql@16.10.0) graphql-playground-html: 1.6.30 http-status: 2.1.0 - next: 15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) path-to-regexp: 6.3.0 - payload: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + payload: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) qs-esm: 7.0.2 - react-diff-viewer-continued: 3.2.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-diff-viewer-continued: 3.2.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2) sass: 1.77.4 - sonner: 1.7.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + sonner: 1.7.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -3513,23 +3567,23 @@ snapshots: - supports-color - typescript - '@payloadcms/richtext-lexical@3.18.0(bvirogffrpuzy2e4p57bv2watq)': + '@payloadcms/richtext-lexical@3.18.0(9d0cbd55753b1430a277687619c49ac8)': dependencies: - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@lexical/headless': 0.21.0 '@lexical/html': 0.21.0 '@lexical/link': 0.21.0 '@lexical/list': 0.21.0 '@lexical/mark': 0.21.0 - '@lexical/react': 0.21.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(yjs@13.6.23) + '@lexical/react': 0.21.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.23) '@lexical/rich-text': 0.21.0 '@lexical/selection': 0.21.0 '@lexical/table': 0.21.0 '@lexical/utils': 0.21.0 - '@payloadcms/next': 3.18.0(@types/react@19.0.7)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/next': 3.18.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@payloadcms/translations': 3.18.0 - '@payloadcms/ui': 3.18.0(@types/react@19.0.7)(monaco-editor@0.52.2)(next@15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/ui': 3.18.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -3540,10 +3594,10 @@ snapshots: mdast-util-from-markdown: 2.0.2 mdast-util-mdx-jsx: 3.1.3 micromark-extension-mdx-jsx: 3.0.1 - payload: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-error-boundary: 4.1.2(react@19.0.0) + payload: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 4.1.2(react@19.2.2) ts-essentials: 10.0.3(typescript@5.5.2) uuid: 10.0.0 transitivePeerDependencies: @@ -3557,33 +3611,33 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.18.0(@types/react@19.0.7)(monaco-editor@0.52.2)(next@15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/ui@3.18.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@monaco-editor/react': 4.6.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@monaco-editor/react': 4.6.0(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/translations': 3.18.0 body-scroll-lock: 4.0.0-beta.0 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) object-to-formdata: 4.5.1 - payload: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + payload: 3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) qs-esm: 7.0.2 - react: 19.0.0 - react-datepicker: 7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-dom: 19.0.0(react@19.0.0) - react-image-crop: 10.1.8(react@19.0.0) - react-select: 5.9.0(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.2 + react-datepicker: 7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-dom: 19.2.2(react@19.2.2) + react-image-crop: 10.1.8(react@19.2.2) + react-select: 5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) scheduler: 0.25.0 - sonner: 1.7.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + sonner: 1.7.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) ts-essentials: 10.0.3(typescript@5.5.2) - use-context-selector: 2.0.0(react@19.0.0)(scheduler@0.25.0) + use-context-selector: 2.0.0(react@19.2.2)(scheduler@0.25.0) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -3696,15 +3750,15 @@ snapshots: '@types/parse-json@4.0.2': {} - '@types/react-dom@19.0.3(@types/react@19.0.7)': + '@types/react-dom@19.2.1(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.7 + '@types/react': 19.2.1 - '@types/react-transition-group@4.4.12(@types/react@19.0.7)': + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.7 + '@types/react': 19.2.1 - '@types/react@19.0.7': + '@types/react@19.2.1': dependencies: csstype: 3.1.3 @@ -4009,18 +4063,6 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - colorette@2.0.20: {} commander@2.20.3: {} @@ -4117,7 +4159,7 @@ snapshots: dequal@2.0.3: {} - detect-libc@2.0.3: + detect-libc@2.1.2: optional: true devlop@1.1.0: @@ -4335,7 +4377,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -4357,7 +4399,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -4748,9 +4790,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.2: - optional: true - is-async-function@2.1.0: dependencies: call-bound: 1.0.3 @@ -5272,28 +5311,26 @@ snapshots: natural-compare@1.4.0: {} - next@15.1.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): + next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): dependencies: - '@next/env': 15.1.6 - '@swc/counter': 0.1.3 + '@next/env': 15.5.8 '@swc/helpers': 0.5.15 - busboy: 1.6.0 caniuse-lite: 1.0.30001695 postcss: 8.4.31 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + styled-jsx: 5.1.6(react@19.2.2) optionalDependencies: - '@next/swc-darwin-arm64': 15.1.6 - '@next/swc-darwin-x64': 15.1.6 - '@next/swc-linux-arm64-gnu': 15.1.6 - '@next/swc-linux-arm64-musl': 15.1.6 - '@next/swc-linux-x64-gnu': 15.1.6 - '@next/swc-linux-x64-musl': 15.1.6 - '@next/swc-win32-arm64-msvc': 15.1.6 - '@next/swc-win32-x64-msvc': 15.1.6 + '@next/swc-darwin-arm64': 15.5.7 + '@next/swc-darwin-x64': 15.5.7 + '@next/swc-linux-arm64-gnu': 15.5.7 + '@next/swc-linux-arm64-musl': 15.5.7 + '@next/swc-linux-x64-gnu': 15.5.7 + '@next/swc-linux-x64-musl': 15.5.7 + '@next/swc-win32-arm64-msvc': 15.5.7 + '@next/swc-win32-x64-msvc': 15.5.7 sass: 1.77.4 - sharp: 0.33.5 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -5405,9 +5442,9 @@ snapshots: path-type@4.0.0: {} - payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2): + payload@3.18.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2): dependencies: - '@monaco-editor/react': 4.6.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@monaco-editor/react': 4.6.0(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@next/env': 15.1.6 '@payloadcms/translations': 3.18.0 '@types/busboy': 1.5.4 @@ -5536,74 +5573,74 @@ snapshots: quick-format-unescaped@4.0.4: {} - react-datepicker@7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-datepicker@7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - '@floating-ui/react': 0.27.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react': 0.27.3(react-dom@19.2.2(react@19.2.2))(react@19.2.2) clsx: 2.1.1 date-fns: 3.6.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react-diff-viewer-continued@3.2.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-diff-viewer-continued@3.2.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@emotion/css': 11.13.5 classnames: 2.5.1 diff: 5.2.0 memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) transitivePeerDependencies: - supports-color - react-dom@19.0.0(react@19.0.0): + react-dom@19.2.2(react@19.2.2): dependencies: - react: 19.0.0 - scheduler: 0.25.0 + react: 19.2.2 + scheduler: 0.27.0 - react-error-boundary@3.1.4(react@19.0.0): + react-error-boundary@3.1.4(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 - react: 19.0.0 + react: 19.2.2 - react-error-boundary@4.1.2(react@19.0.0): + react-error-boundary@4.1.2(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 - react: 19.0.0 + react: 19.2.2 - react-image-crop@10.1.8(react@19.0.0): + react-image-crop@10.1.8(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 react-is@16.13.1: {} - react-select@5.9.0(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-select@5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 '@emotion/cache': 11.14.0 - '@emotion/react': 11.14.0(@types/react@19.0.7)(react@19.0.0) + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.2) '@floating-ui/dom': 1.6.13 - '@types/react-transition-group': 4.4.12(@types/react@19.0.7) + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - use-isomorphic-layout-effect: 1.2.0(@types/react@19.0.7)(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + use-isomorphic-layout-effect: 1.2.0(@types/react@19.2.1)(react@19.2.2) transitivePeerDependencies: - '@types/react' - supports-color - react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-transition-group@4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react@19.0.0: {} + react@19.2.2: {} readdirp@3.6.0: dependencies: @@ -5694,6 +5731,8 @@ snapshots: scheduler@0.25.0: {} + scheduler@0.27.0: {} + scmp@2.1.0: {} secure-json-parse@2.7.0: {} @@ -5702,6 +5741,9 @@ snapshots: semver@7.6.3: {} + semver@7.7.3: + optional: true + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5724,31 +5766,36 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 - sharp@0.33.5: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.3 - semver: 7.6.3 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -5787,11 +5834,6 @@ snapshots: sift@17.1.3: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - simple-wcswidth@1.0.1: {} sisteransi@1.0.5: {} @@ -5800,10 +5842,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@1.7.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + sonner@1.7.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) source-map-js@1.2.1: {} @@ -5889,10 +5931,10 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.3.1 - styled-jsx@5.1.6(react@19.0.0): + styled-jsx@5.1.6(react@19.2.2): dependencies: client-only: 0.0.1 - react: 19.0.0 + react: 19.2.2 stylis@4.2.0: {} @@ -6037,16 +6079,16 @@ snapshots: dependencies: punycode: 2.3.1 - use-context-selector@2.0.0(react@19.0.0)(scheduler@0.25.0): + use-context-selector@2.0.0(react@19.2.2)(scheduler@0.25.0): dependencies: - react: 19.0.0 + react: 19.2.2 scheduler: 0.25.0 - use-isomorphic-layout-effect@1.2.0(@types/react@19.0.7)(react@19.0.0): + use-isomorphic-layout-effect@1.2.0(@types/react@19.2.1)(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.7 + '@types/react': 19.2.1 utf8-byte-length@1.0.5: {} diff --git a/examples/custom-server/package.json b/examples/custom-server/package.json index 7da89cfe089..ea0def6af34 100644 --- a/examples/custom-server/package.json +++ b/examples/custom-server/package.json @@ -17,7 +17,7 @@ "cross-env": "^7.0.3", "express": "^4.21.1", "graphql": "^16.8.1", - "next": "15.4.8", + "next": "15.4.9", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1" diff --git a/examples/custom-server/pnpm-lock.yaml b/examples/custom-server/pnpm-lock.yaml new file mode 100644 index 00000000000..fb363cdba6f --- /dev/null +++ b/examples/custom-server/pnpm-lock.yaml @@ -0,0 +1,6436 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@payloadcms/db-mongodb': + specifier: latest + version: 3.68.2(@aws-sdk/credential-providers@3.948.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3)) + '@payloadcms/next': + specifier: latest + version: 3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + '@payloadcms/payload-cloud': + specifier: latest + version: 3.68.2(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3)) + '@payloadcms/richtext-lexical': + specifier: latest + version: 3.68.2(@faceless-ui/modal@3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)(yjs@13.6.27) + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + express: + specifier: ^4.21.1 + version: 4.22.1 + graphql: + specifier: ^16.8.1 + version: 16.12.0 + next: + specifier: 15.4.9 + version: 15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + payload: + specifier: latest + version: 3.68.2(graphql@16.12.0)(typescript@5.9.3) + react: + specifier: ^19.2.1 + version: 19.2.2 + react-dom: + specifier: ^19.2.1 + version: 19.2.2(react@19.2.2) + devDependencies: + '@types/express': + specifier: ^5.0.0 + version: 5.0.6 + '@types/node': + specifier: ^18.11.5 + version: 18.19.130 + '@types/react': + specifier: 19.2.1 + version: 19.2.1 + '@types/react-dom': + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) + nodemon: + specifier: ^3.1.7 + version: 3.1.11 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@18.19.130)(typescript@5.9.3) + tsx: + specifier: ^4.19.2 + version: 4.21.0 + typescript: + specifier: ^5.7.2 + version: 5.9.3 + +packages: + + '@apidevtools/json-schema-ref-parser@11.9.3': + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} + engines: {node: '>= 16'} + + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/crc32c@5.2.0': + resolution: {integrity: sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==} + + '@aws-crypto/sha1-browser@5.2.0': + resolution: {integrity: sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@1.2.2': + resolution: {integrity: sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@1.2.2': + resolution: {integrity: sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-cognito-identity@3.948.0': + resolution: {integrity: sha512-xuf0zODa1zxiCDEcAW0nOsbkXHK9QnK6KFsCatSdcIsg1zIaGCui0Cg3HCm/gjoEgv+4KkEpYmzdcT5piedzxA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/client-s3@3.948.0': + resolution: {integrity: sha512-uvEjds8aYA9SzhBS8RKDtsDUhNV9VhqKiHTcmvhM7gJO92q0WTn8/QeFTdNyLc6RxpiDyz+uBxS7PcdNiZzqfA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/client-sso@3.948.0': + resolution: {integrity: sha512-iWjchXy8bIAVBUsKnbfKYXRwhLgRg3EqCQ5FTr3JbR+QR75rZm4ZOYXlvHGztVTmtAZ+PQVA1Y4zO7v7N87C0A==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/core@3.947.0': + resolution: {integrity: sha512-Khq4zHhuAkvCFuFbgcy3GrZTzfSX7ZIjIcW1zRDxXRLZKRtuhnZdonqTUfaWi5K42/4OmxkYNpsO7X7trQOeHw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-cognito-identity@3.948.0': + resolution: {integrity: sha512-qWzS4aJj09sHJ4ZPLP3UCgV2HJsqFRNtseoDlvmns8uKq4ShaqMoqJrN6A9QTZT7lEBjPFsfVV4Z7Eh6a0g3+g==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-env@3.947.0': + resolution: {integrity: sha512-VR2V6dRELmzwAsCpK4GqxUi6UW5WNhAXS9F9AzWi5jvijwJo3nH92YNJUP4quMpgFZxJHEWyXLWgPjh9u0zYOA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-http@3.947.0': + resolution: {integrity: sha512-inF09lh9SlHj63Vmr5d+LmwPXZc2IbK8lAruhOr3KLsZAIHEgHgGPXWDC2ukTEMzg0pkexQ6FOhXXad6klK4RA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-ini@3.948.0': + resolution: {integrity: sha512-Cl//Qh88e8HBL7yYkJNpF5eq76IO6rq8GsatKcfVBm7RFVxCqYEPSSBtkHdbtNwQdRQqAMXc6E/lEB/CZUDxnA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-login@3.948.0': + resolution: {integrity: sha512-gcKO2b6eeTuZGp3Vvgr/9OxajMrD3W+FZ2FCyJox363ZgMoYJsyNid1vuZrEuAGkx0jvveLXfwiVS0UXyPkgtw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-node@3.948.0': + resolution: {integrity: sha512-ep5vRLnrRdcsP17Ef31sNN4g8Nqk/4JBydcUJuFRbGuyQtrZZrVT81UeH2xhz6d0BK6ejafDB9+ZpBjXuWT5/Q==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-process@3.947.0': + resolution: {integrity: sha512-WpanFbHe08SP1hAJNeDdBDVz9SGgMu/gc0XJ9u3uNpW99nKZjDpvPRAdW7WLA4K6essMjxWkguIGNOpij6Do2Q==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-sso@3.948.0': + resolution: {integrity: sha512-gqLhX1L+zb/ZDnnYbILQqJ46j735StfWV5PbDjxRzBKS7GzsiYoaf6MyHseEopmWrez5zl5l6aWzig7UpzSeQQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.948.0': + resolution: {integrity: sha512-MvYQlXVoJyfF3/SmnNzOVEtANRAiJIObEUYYyjTqKZTmcRIVVky0tPuG26XnB8LmTYgtESwJIZJj/Eyyc9WURQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/credential-providers@3.948.0': + resolution: {integrity: sha512-puFIZzSxByrTS7Ffn+zIjxlyfI0ELjjwvISVUTAZPmH5Jl95S39+A+8MOOALtFQcxLO7UEIiJFJIIkNENK+60w==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/lib-storage@3.948.0': + resolution: {integrity: sha512-dY7wISfWgEqSHGps0DkQiDjHhCqR7bc0mMrBHZ810/j12uzhTakAcb9FlF7mFWkX6zEvz2kjxF4r91lBwNqt5w==} + engines: {node: '>=18.0.0'} + peerDependencies: + '@aws-sdk/client-s3': ^3.948.0 + + '@aws-sdk/middleware-bucket-endpoint@3.936.0': + resolution: {integrity: sha512-XLSVVfAorUxZh6dzF+HTOp4R1B5EQcdpGcPliWr0KUj2jukgjZEcqbBmjyMF/p9bmyQsONX80iURF1HLAlW0qg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-expect-continue@3.936.0': + resolution: {integrity: sha512-Eb4ELAC23bEQLJmUMYnPWcjD3FZIsmz2svDiXEcxRkQU9r7NRID7pM7C5NPH94wOfiCk0b2Y8rVyFXW0lGQwbA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-flexible-checksums@3.947.0': + resolution: {integrity: sha512-kXXxS2raNESNO+zR0L4YInVjhcGGNI2Mx0AE1ThRhDkAt2se3a+rGf9equ9YvOqA1m8Jl/GSI8cXYvSxXmS9Ag==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-host-header@3.936.0': + resolution: {integrity: sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-location-constraint@3.936.0': + resolution: {integrity: sha512-SCMPenDtQMd9o5da9JzkHz838w3327iqXk3cbNnXWqnNRx6unyW8FL0DZ84gIY12kAyVHz5WEqlWuekc15ehfw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-logger@3.936.0': + resolution: {integrity: sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.948.0': + resolution: {integrity: sha512-Qa8Zj+EAqA0VlAVvxpRnpBpIWJI9KUwaioY1vkeNVwXPlNaz9y9zCKVM9iU9OZ5HXpoUg6TnhATAHXHAE8+QsQ==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-sdk-s3@3.947.0': + resolution: {integrity: sha512-DS2tm5YBKhPW2PthrRBDr6eufChbwXe0NjtTZcYDfUCXf0OR+W6cIqyKguwHMJ+IyYdey30AfVw9/Lb5KB8U8A==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-ssec@3.936.0': + resolution: {integrity: sha512-/GLC9lZdVp05ozRik5KsuODR/N7j+W+2TbfdFL3iS+7un+gnP6hC8RDOZd6WhpZp7drXQ9guKiTAxkZQwzS8DA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/middleware-user-agent@3.947.0': + resolution: {integrity: sha512-7rpKV8YNgCP2R4F9RjWZFcD2R+SO/0R4VHIbY9iZJdH2MzzJ8ZG7h8dZ2m8QkQd1fjx4wrFJGGPJUTYXPV3baA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/nested-clients@3.948.0': + resolution: {integrity: sha512-zcbJfBsB6h254o3NuoEkf0+UY1GpE9ioiQdENWv7odo69s8iaGBEQ4BDpsIMqcuiiUXw1uKIVNxCB1gUGYz8lw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/region-config-resolver@3.936.0': + resolution: {integrity: sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.947.0': + resolution: {integrity: sha512-UaYmzoxf9q3mabIA2hc4T6x5YSFUG2BpNjAZ207EA1bnQMiK+d6vZvb83t7dIWL/U1de1sGV19c1C81Jf14rrA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/token-providers@3.948.0': + resolution: {integrity: sha512-V487/kM4Teq5dcr1t5K6eoUKuqlGr9FRWL3MIMukMERJXHZvio6kox60FZ/YtciRHRI75u14YUqm2Dzddcu3+A==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/types@3.936.0': + resolution: {integrity: sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-arn-parser@3.893.0': + resolution: {integrity: sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-endpoints@3.936.0': + resolution: {integrity: sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-locate-window@3.893.0': + resolution: {integrity: sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg==} + engines: {node: '>=18.0.0'} + + '@aws-sdk/util-user-agent-browser@3.936.0': + resolution: {integrity: sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw==} + + '@aws-sdk/util-user-agent-node@3.947.0': + resolution: {integrity: sha512-+vhHoDrdbb+zerV4noQk1DHaUMNzWFWPpPYjVTwW2186k5BEJIecAMChYkghRrBVJ3KPWP1+JnZwOd72F3d4rQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/util-utf8-browser@3.259.0': + resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + + '@aws-sdk/xml-builder@3.930.0': + resolution: {integrity: sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA==} + engines: {node: '>=18.0.0'} + + '@aws/lambda-invoke-store@0.2.2': + resolution: {integrity: sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg==} + engines: {node: '>=18.0.0'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@borewit/text-codec@0.1.1': + resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@date-fns/tz@1.2.0': + resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==} + + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.0.8': + resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/sortable@7.0.2': + resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} + peerDependencies: + '@dnd-kit/core': ^6.0.7 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + peerDependencies: + react: '>=16.8.0' + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.1': + resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.27.1': + resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.27.1': + resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.27.1': + resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.27.1': + resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.1': + resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.1': + resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.1': + resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.27.1': + resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.27.1': + resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.1': + resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.27.1': + resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.1': + resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.1': + resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.1': + resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.1': + resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.1': + resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.27.1': + resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.1': + resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.1': + resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.1': + resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.27.1': + resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.1': + resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.1': + resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.1': + resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.1': + resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@faceless-ui/modal@3.0.0': + resolution: {integrity: sha512-o3oEFsot99EQ8RJc1kL3s/nNMHX+y+WMXVzSSmca9L0l2MR6ez2QM1z1yIelJX93jqkLXQ9tW+R9tmsYa+O4Qg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@faceless-ui/scroll-info@2.0.0': + resolution: {integrity: sha512-BkyJ9OQ4bzpKjE3UhI8BhcG36ZgfB4run8TmlaR4oMFUbl59dfyarNfjveyimrxIso9RhFEja/AJ5nQmbcR9hw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@faceless-ui/window-info@3.0.1': + resolution: {integrity: sha512-uPjdJYE/j7hqVNelE9CRUNOeXuXDdPxR4DMe+oz3xwyZi2Y4CxsfpfdPTqqwmNAZa1P33O+ZiCyIkBEeNed0kw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.27.16': + resolution: {integrity: sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==} + peerDependencies: + react: '>=17.0.0' + react-dom: '>=17.0.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@lexical/clipboard@0.35.0': + resolution: {integrity: sha512-ko7xSIIiayvDiqjNDX6fgH9RlcM6r9vrrvJYTcfGVBor5httx16lhIi0QJZ4+RNPvGtTjyFv4bwRmsixRRwImg==} + + '@lexical/code@0.35.0': + resolution: {integrity: sha512-ox4DZwETQ9IA7+DS6PN8RJNwSAF7RMjL7YTVODIqFZ5tUFIf+5xoCHbz7Fll0Bvixlp12hVH90xnLwTLRGpkKw==} + + '@lexical/devtools-core@0.35.0': + resolution: {integrity: sha512-C2wwtsMCR6ZTfO0TqpSM17RLJWyfHmifAfCTjFtOJu15p3M6NO/nHYK5Mt7YMQteuS89mOjB4ng8iwoLEZ6QpQ==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/dragon@0.35.0': + resolution: {integrity: sha512-SL6mT5pcqrt6hEbJ16vWxip5+r3uvMd0bQV5UUxuk+cxIeuP86iTgRh0HFR7SM2dRTYovL6/tM/O+8QLAUGTIg==} + + '@lexical/hashtag@0.35.0': + resolution: {integrity: sha512-LYJWzXuO2ZjKsvQwrLkNZiS2TsjwYkKjlDgtugzejquTBQ/o/nfSn/MmVx6EkYLOYizaJemmZbz3IBh+u732FA==} + + '@lexical/headless@0.35.0': + resolution: {integrity: sha512-UPmCqOsdGGC7/8Fkae2ADkTQfxTZOKxNEVKuqPfCkFs4Bag3s4z3V61jE+wYzqyU8eJh4DqZYSHoPzZCj8P9jg==} + + '@lexical/history@0.35.0': + resolution: {integrity: sha512-onjDRLLxGbCfHexSxxrQaDaieIHyV28zCDrbxR5dxTfW8F8PxjuNyuaG0z6o468AXYECmclxkP+P4aT6poHEpQ==} + + '@lexical/html@0.35.0': + resolution: {integrity: sha512-rXGFE5S5rKsg3tVnr1s4iEgOfCApNXGpIFI3T2jGEShaCZ5HLaBY9NVBXnE9Nb49e9bkDkpZ8FZd1qokCbQXbw==} + + '@lexical/link@0.35.0': + resolution: {integrity: sha512-+0Wx6cBwO8TfdMzpkYFacsmgFh8X1rkiYbq3xoLvk3qV8upYxaMzK1s8Q1cpKmWyI0aZrU6z7fiK4vUqB7+69w==} + + '@lexical/list@0.35.0': + resolution: {integrity: sha512-owsmc8iwgExBX8sFe8fKTiwJVhYULt9hD1RZ/HwfaiEtRZZkINijqReOBnW2mJfRxBzhFSWc4NG3ISB+fHYzqw==} + + '@lexical/mark@0.35.0': + resolution: {integrity: sha512-W0hwMTAVeexvpk9/+J6n1G/sNkpI/Meq1yeDazahFLLAwXLHtvhIAq2P/klgFknDy1hr8X7rcsQuN/bqKcKHYg==} + + '@lexical/markdown@0.35.0': + resolution: {integrity: sha512-BlNyXZAt4gWidMw0SRWrhBETY1BpPglFBZI7yzfqukFqgXRh7HUQA28OYeI/nsx9pgNob8TiUduUwShqqvOdEA==} + + '@lexical/offset@0.35.0': + resolution: {integrity: sha512-DRE4Df6qYf2XiV6foh6KpGNmGAv2ANqt3oVXpyS6W8hTx3+cUuAA1APhCZmLNuU107um4zmHym7taCu6uXW5Yg==} + + '@lexical/overflow@0.35.0': + resolution: {integrity: sha512-B25YvnJQTGlZcrNv7b0PJBLWq3tl8sql497OHfYYLem7EOMPKKDGJScJAKM/91D4H/mMAsx5gnA/XgKobriuTg==} + + '@lexical/plain-text@0.35.0': + resolution: {integrity: sha512-lwBCUNMJf7Gujp2syVWMpKRahfbTv5Wq+H3HK1Q1gKH1P2IytPRxssCHvexw9iGwprSyghkKBlbF3fGpEdIJvQ==} + + '@lexical/react@0.35.0': + resolution: {integrity: sha512-uYAZSqumH8tRymMef+A0f2hQvMwplKK9DXamcefnk3vSNDHHqRWQXpiUo6kD+rKWuQmMbVa5RW4xRQebXEW+1A==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/rich-text@0.35.0': + resolution: {integrity: sha512-qEHu8g7vOEzz9GUz1VIUxZBndZRJPh9iJUFI+qTDHj+tQqnd5LCs+G9yz6jgNfiuWWpezTp0i1Vz/udNEuDPKQ==} + + '@lexical/selection@0.35.0': + resolution: {integrity: sha512-mMtDE7Q0nycXdFTTH/+ta6EBrBwxBB4Tg8QwsGntzQ1Cq//d838dpXpFjJOqHEeVHUqXpiuj+cBG8+bvz/rPRw==} + + '@lexical/table@0.35.0': + resolution: {integrity: sha512-9jlTlkVideBKwsEnEkqkdg7A3mije1SvmfiqoYnkl1kKJCLA5iH90ywx327PU0p+bdnURAytWUeZPXaEuEl2OA==} + + '@lexical/text@0.35.0': + resolution: {integrity: sha512-uaMh46BkysV8hK8wQwp5g/ByZW+2hPDt8ahAErxtf8NuzQem1FHG/f5RTchmFqqUDVHO3qLNTv4AehEGmXv8MA==} + + '@lexical/utils@0.35.0': + resolution: {integrity: sha512-2H393EYDnFznYCDFOW3MHiRzwEO5M/UBhtUjvTT+9kc+qhX4U3zc8ixQalo5UmZ5B2nh7L/inXdTFzvSRXtsRA==} + + '@lexical/yjs@0.35.0': + resolution: {integrity: sha512-3DSP7QpmTGYU9bN/yljP0PIao4tNIQtsR4ycauWNSawxs/GQCZtSmAPcLRnCm6qpqsDDjUtKjO/1Ej8FRp0m0w==} + peerDependencies: + yjs: '>=13.5.22' + + '@monaco-editor/loader@1.7.0': + resolution: {integrity: sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==} + + '@monaco-editor/react@4.7.0': + resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} + peerDependencies: + monaco-editor: '>= 0.25.0 < 1' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@mongodb-js/saslprep@1.4.0': + resolution: {integrity: sha512-ZHzx7Z3rdlWL1mECydvpryWN/ETXJiCxdgQKTAH+djzIPe77HdnSizKBDi1TVDXZjXyOj2IqEG/vPw71ULF06w==} + + '@next/env@15.4.9': + resolution: {integrity: sha512-OYR0RulK5phnbxxzcLE4/ECgfx1PL3EHrDbjyelJ7jauaO+/Qvj5gG8JPMltB51CygC2KrZ0aAfYLjPYjYY17A==} + + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + + '@next/swc-darwin-arm64@15.4.8': + resolution: {integrity: sha512-Pf6zXp7yyQEn7sqMxur6+kYcywx5up1J849psyET7/8pG2gQTVMjU3NzgIt8SeEP5to3If/SaWmaA6H6ysBr1A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.4.8': + resolution: {integrity: sha512-xla6AOfz68a6kq3gRQccWEvFC/VRGJmA/QuSLENSO7CZX5WIEkSz7r1FdXUjtGCQ1c2M+ndUAH7opdfLK1PQbw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.4.8': + resolution: {integrity: sha512-y3fmp+1Px/SJD+5ntve5QLZnGLycsxsVPkTzAc3zUiXYSOlTPqT8ynfmt6tt4fSo1tAhDPmryXpYKEAcoAPDJw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@15.4.8': + resolution: {integrity: sha512-DX/L8VHzrr1CfwaVjBQr3GWCqNNFgyWJbeQ10Lx/phzbQo3JNAxUok1DZ8JHRGcL6PgMRgj6HylnLNndxn4Z6A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@15.4.8': + resolution: {integrity: sha512-9fLAAXKAL3xEIFdKdzG5rUSvSiZTLLTCc6JKq1z04DR4zY7DbAPcRvNm3K1inVhTiQCs19ZRAgUerHiVKMZZIA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@15.4.8': + resolution: {integrity: sha512-s45V7nfb5g7dbS7JK6XZDcapicVrMMvX2uYgOHP16QuKH/JA285oy6HcxlKqwUNaFY/UC6EvQ8QZUOo19cBKSA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@15.4.8': + resolution: {integrity: sha512-KjgeQyOAq7t/HzAJcWPGA8X+4WY03uSCZ2Ekk98S9OgCFsb6lfBE3dbUzUuEQAN2THbwYgFfxX2yFTCMm8Kehw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.4.8': + resolution: {integrity: sha512-Exsmf/+42fWVnLMaZHzshukTBxZrSwuuLKFvqhGHJ+mC1AokqieLY/XzAl3jc/CqhXLqLY3RRjkKJ9YnLPcRWg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@payloadcms/db-mongodb@3.68.2': + resolution: {integrity: sha512-UMofU0wabU9gmelV1v6/6fyecuZXp7CplH4B2zHbsukl02zQ6nKN1I1JLcFSAmAAg/FPDz/HkpHKM4zNuI0Rig==} + peerDependencies: + payload: 3.68.2 + + '@payloadcms/email-nodemailer@3.68.2': + resolution: {integrity: sha512-3c1XhsyVAPeJVvk/r3/l5vDoOdTFkp1ddUUfQs13t3cki/toCy2Rc/yQN+RqQ8Snuoe5+egCJB859RBCsPRJ+w==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + payload: 3.68.2 + + '@payloadcms/graphql@3.68.2': + resolution: {integrity: sha512-7RjoVXWgHmod7Dps24Z/0G8vXA0QUa+C2BL68gOnKBoWHsPB7PcaUp7luPizkW3jjfZLKnGkhvrI6CiD60bDsg==} + hasBin: true + peerDependencies: + graphql: ^16.8.1 + payload: 3.68.2 + + '@payloadcms/next@3.68.2': + resolution: {integrity: sha512-Pb3ZVPe3XbAJ3Th8nbyBnuaCMP4ZlockMczl2fyrethJ379pXPPBGjrFECPoaHhKjQPIEUVxo7WZjY8Yf/qBmg==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + graphql: ^16.8.1 + next: ^15.4.8 + payload: 3.68.2 + + '@payloadcms/payload-cloud@3.68.2': + resolution: {integrity: sha512-koRbxJOjXIw5M3vyOeLmn10DJvpDNfqepyfzPD7raS4sdVvEdkioPbHqSftlNnU2ipOUTkUSgNyZVAr6yi+eBg==} + peerDependencies: + payload: 3.68.2 + + '@payloadcms/richtext-lexical@3.68.2': + resolution: {integrity: sha512-plPFLcCosONsuiTMIwyIZLTpxhIy1G7QajrejTZwRpXMCzB2xfLgSCDoiIg4KHLVIZV/UqSxtUrpYk7+zEpL2w==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + '@faceless-ui/modal': 3.0.0 + '@faceless-ui/scroll-info': 2.0.0 + '@payloadcms/next': 3.68.2 + payload: 3.68.2 + react: ^19.0.1 || ^19.1.2 || ^19.2.1 + react-dom: ^19.0.1 || ^19.1.2 || ^19.2.1 + + '@payloadcms/translations@3.68.2': + resolution: {integrity: sha512-HIfB6QYknjFGHs83ynUYyRgyGRKAEE7DRF0VMscwX0RtXNEtg3DMM+bCyTu5AZXr1hWrQ4xUrnVh7Vaj1yqWFQ==} + + '@payloadcms/ui@3.68.2': + resolution: {integrity: sha512-cKjdy0FucOTE+wxh5KZ7oTZQOvOxJFnmhfJd8av6HFoREt0r5kmnwc5rssdEgK2T1sJ2GcE4bZ0gVxB2vV6rCQ==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + next: ^15.2.6 || ^15.3.6 || ^15.4.8 || ^15.5.7 + payload: 3.68.2 + react: ^19.0.1 || ^19.1.2 || ^19.2.1 + react-dom: ^19.0.1 || ^19.1.2 || ^19.2.1 + + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + + '@smithy/abort-controller@4.2.5': + resolution: {integrity: sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader-native@4.2.1': + resolution: {integrity: sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ==} + engines: {node: '>=18.0.0'} + + '@smithy/chunked-blob-reader@5.2.0': + resolution: {integrity: sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA==} + engines: {node: '>=18.0.0'} + + '@smithy/config-resolver@4.4.3': + resolution: {integrity: sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw==} + engines: {node: '>=18.0.0'} + + '@smithy/core@3.18.7': + resolution: {integrity: sha512-axG9MvKhMWOhFbvf5y2DuyTxQueO0dkedY9QC3mAfndLosRI/9LJv8WaL0mw7ubNhsO4IuXX9/9dYGPFvHrqlw==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.2.5': + resolution: {integrity: sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-codec@4.2.5': + resolution: {integrity: sha512-Ogt4Zi9hEbIP17oQMd68qYOHUzmH47UkK7q7Gl55iIm9oKt27MUGrC5JfpMroeHjdkOliOA4Qt3NQ1xMq/nrlA==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-browser@4.2.5': + resolution: {integrity: sha512-HohfmCQZjppVnKX2PnXlf47CW3j92Ki6T/vkAT2DhBR47e89pen3s4fIa7otGTtrVxmj7q+IhH0RnC5kpR8wtw==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-config-resolver@4.3.5': + resolution: {integrity: sha512-ibjQjM7wEXtECiT6my1xfiMH9IcEczMOS6xiCQXoUIYSj5b1CpBbJ3VYbdwDy8Vcg5JHN7eFpOCGk8nyZAltNQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-node@4.2.5': + resolution: {integrity: sha512-+elOuaYx6F2H6x1/5BQP5ugv12nfJl66GhxON8+dWVUEDJ9jah/A0tayVdkLRP0AeSac0inYkDz5qBFKfVp2Gg==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-universal@4.2.5': + resolution: {integrity: sha512-G9WSqbST45bmIFaeNuP/EnC19Rhp54CcVdX9PDL1zyEB514WsDVXhlyihKlGXnRycmHNmVv88Bvvt4EYxWef/Q==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.3.6': + resolution: {integrity: sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-blob-browser@4.2.6': + resolution: {integrity: sha512-8P//tA8DVPk+3XURk2rwcKgYwFvwGwmJH/wJqQiSKwXZtf/LiZK+hbUZmPj/9KzM+OVSwe4o85KTp5x9DUZTjw==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-node@4.2.5': + resolution: {integrity: sha512-DpYX914YOfA3UDT9CN1BM787PcHfWRBB43fFGCYrZFUH0Jv+5t8yYl+Pd5PW4+QzoGEDvn5d5QIO4j2HyYZQSA==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-stream-node@4.2.5': + resolution: {integrity: sha512-6+do24VnEyvWcGdHXomlpd0m8bfZePpUKBy7m311n+JuRwug8J4dCanJdTymx//8mi0nlkflZBvJe+dEO/O12Q==} + engines: {node: '>=18.0.0'} + + '@smithy/invalid-dependency@4.2.5': + resolution: {integrity: sha512-2L2erASEro1WC5nV+plwIMxrTXpvpfzl4e+Nre6vBVRR2HKeGGcvpJyyL3/PpiSg+cJG2KpTmZmq934Olb6e5A==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.2.0': + resolution: {integrity: sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ==} + engines: {node: '>=18.0.0'} + + '@smithy/md5-js@4.2.5': + resolution: {integrity: sha512-Bt6jpSTMWfjCtC0s79gZ/WZ1w90grfmopVOWqkI2ovhjpD5Q2XRXuecIPB9689L2+cCySMbaXDhBPU56FKNDNg==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@4.2.5': + resolution: {integrity: sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@4.3.14': + resolution: {integrity: sha512-v0q4uTKgBM8dsqGjqsabZQyH85nFaTnFcgpWU1uydKFsdyyMzfvOkNum9G7VK+dOP01vUnoZxIeRiJ6uD0kjIg==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@4.4.14': + resolution: {integrity: sha512-Z2DG8Ej7FyWG1UA+7HceINtSLzswUgs2np3sZX0YBBxCt+CXG4QUxv88ZDS3+2/1ldW7LqtSY1UO/6VQ1pND8Q==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.2.6': + resolution: {integrity: sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@4.2.5': + resolution: {integrity: sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@4.3.5': + resolution: {integrity: sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.4.5': + resolution: {integrity: sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.2.5': + resolution: {integrity: sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@5.3.5': + resolution: {integrity: sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@4.2.5': + resolution: {integrity: sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@4.2.5': + resolution: {integrity: sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@4.2.5': + resolution: {integrity: sha512-8fEvK+WPE3wUAcDvqDQG1Vk3ANLR8Px979te96m84CbKAjBVf25rPYSzb4xU4hlTyho7VhOGnh5i62D/JVF0JQ==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@4.4.0': + resolution: {integrity: sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.3.5': + resolution: {integrity: sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@4.9.10': + resolution: {integrity: sha512-Jaoz4Jw1QYHc1EFww/E6gVtNjhoDU+gwRKqXP6C3LKYqqH2UQhP8tMP3+t/ePrhaze7fhLE8vS2q6vVxBANFTQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.9.0': + resolution: {integrity: sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.2.5': + resolution: {integrity: sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@4.3.0': + resolution: {integrity: sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@4.2.0': + resolution: {integrity: sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@4.2.1': + resolution: {integrity: sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.2.0': + resolution: {integrity: sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew==} + engines: {node: '>=18.0.0'} + + '@smithy/util-config-provider@4.2.0': + resolution: {integrity: sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-browser@4.3.13': + resolution: {integrity: sha512-hlVLdAGrVfyNei+pKIgqDTxfu/ZI2NSyqj4IDxKd5bIsIqwR/dSlkxlPaYxFiIaDVrBy0he8orsFy+Cz119XvA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-node@4.2.16': + resolution: {integrity: sha512-F1t22IUiJLHrxW9W1CQ6B9PN+skZ9cqSuzB18Eh06HrJPbjsyZ7ZHecAKw80DQtyGTRcVfeukKaCRYebFwclbg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-endpoints@3.2.5': + resolution: {integrity: sha512-3O63AAWu2cSNQZp+ayl9I3NapW1p1rR5mlVHcF6hAB1dPZUQFfRPYtplWX/3xrzWthPGj5FqB12taJJCfH6s8A==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@4.2.0': + resolution: {integrity: sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@4.2.5': + resolution: {integrity: sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-retry@4.2.5': + resolution: {integrity: sha512-GBj3+EZBbN4NAqJ/7pAhsXdfzdlznOh8PydUijy6FpNIMnHPSMO2/rP4HKu+UFeikJxShERk528oy7GT79YiJg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@4.5.6': + resolution: {integrity: sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-uri-escape@4.2.0': + resolution: {integrity: sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.2.0': + resolution: {integrity: sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-waiter@4.2.5': + resolution: {integrity: sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g==} + engines: {node: '>=18.0.0'} + + '@smithy/uuid@1.1.0': + resolution: {integrity: sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw==} + engines: {node: '>=18.0.0'} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@tsconfig/node10@1.0.12': + resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/acorn@4.0.6': + resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} + + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + + '@types/busboy@1.5.4': + resolution: {integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/express-serve-static-core@5.1.0': + resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==} + + '@types/express@5.0.6': + resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/lodash@4.17.21': + resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@18.19.130': + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react-transition-group@4.4.12': + resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} + peerDependencies: + '@types/react': '*' + + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} + + '@types/send@1.2.1': + resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} + + '@types/serve-static@2.2.0': + resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@11.0.5': + resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} + + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + amazon-cognito-identity-js@6.3.16: + resolution: {integrity: sha512-HPGSBGD6Q36t99puWh0LnptxO/4icnk2kqIQ9cTJ2tFQo5NMUnWQIgtrTAk8nm+caqUbjDzXzG56GBjI2tS6jQ==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + body-parser@1.20.4: + resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + body-scroll-lock@4.0.0-beta.0: + resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==} + + bowser@2.13.1: + resolution: {integrity: sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + bson-objectid@2.0.4: + resolution: {integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==} + + bson@6.10.4: + resolution: {integrity: sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==} + engines: {node: '>=16.20.1'} + + buffer@4.9.2: + resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + + buffer@5.6.0: + resolution: {integrity: sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001760: + resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + charenc@0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + console-table-printer@2.12.1: + resolution: {integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==} + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + cookie-signature@1.0.7: + resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + croner@9.1.0: + resolution: {integrity: sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==} + engines: {node: '>=18.0'} + + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crypt@0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + + cssfilter@0.0.10: + resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + dataloader@2.2.3: + resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==} + + date-fns@3.6.0: + resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.27.1: + resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + express@4.22.1: + resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} + engines: {node: '>= 0.10.0'} + + fast-base64-decode@1.0.0: + resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} + + fast-copy@3.0.2: + resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fast-xml-parser@5.2.5: + resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} + hasBin: true + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-type@19.3.0: + resolution: {integrity: sha512-mROwiKLZf/Kwa/2Rol+OOZQn1eyTkPB3ZTwC0ExY6OLFCbgxHYZvBm7xI77NvfZFMKBsmuXfmLJnD4eEftEhrA==} + engines: {node: '>=18'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@1.3.2: + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} + engines: {node: '>= 0.8'} + + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + + focus-trap@7.5.4: + resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graphql-http@1.22.4: + resolution: {integrity: sha512-OC3ucK988teMf+Ak/O+ZJ0N2ukcgrEurypp8ePyJFWq83VzwRAmHxxr+XxrMpxO/FIwI4a7m/Fzv3tWGJv0wPA==} + engines: {node: '>=12'} + peerDependencies: + graphql: '>=0.11 <=16' + + graphql-playground-html@1.6.30: + resolution: {integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==} + + graphql-scalars@1.22.2: + resolution: {integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==} + engines: {node: '>=10'} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + + graphql@16.12.0: + resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + http-status@2.1.0: + resolution: {integrity: sha512-O5kPr7AW7wYd/BBiOezTwnVAnmSNFY+J7hlZD2X5IOxVBetjcHAiTXhzj0gMrnojQlwy+UT1/Y3H3vJ3UlmvLA==} + engines: {node: '>= 0.4.0'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore-by-default@1.0.1: + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + + image-size@2.0.2: + resolution: {integrity: sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==} + engines: {node: '>=16.x'} + hasBin: true + + immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + ipaddr.js@2.2.0: + resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} + engines: {node: '>= 10'} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isomorphic-unfetch@3.1.0: + resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} + + isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + + jose@5.9.6: + resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-cookie@2.2.1: + resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-to-typescript@15.0.3: + resolution: {integrity: sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==} + engines: {node: '>=16.0.0'} + hasBin: true + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + jsox@1.2.121: + resolution: {integrity: sha512-9Ag50tKhpTwS6r5wh3MJSAvpSof0UBr39Pto8OnzFT32Z/pAbxAsKHzyvsyMEHVslELvHyO/4/jaQELHk8wDcw==} + hasBin: true + + kareem@2.6.3: + resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==} + engines: {node: '>=12.0.0'} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + lexical@0.35.0: + resolution: {integrity: sha512-3VuV8xXhh5xJA6tzvfDvE0YBCMkIZUmxtRilJQDDdCgJCc+eut6qAv2qbN+pbqvarqcQqPN1UF+8YvsjmyOZpw==} + + lib0@0.2.114: + resolution: {integrity: sha512-gcxmNFzA4hv8UYi8j43uPlQ7CGcyMJ2KQb5kZASw6SnAKAf10hK12i2fjrS3Cl/ugZa5Ui6WwIu1/6MIXiHttQ==} + engines: {node: '>=16'} + hasBin: true + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + marked@14.0.0: + resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} + engines: {node: '>= 18'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + md5@2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-mdx-jsx@3.1.3: + resolution: {integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + memoize-one@6.0.0: + resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-mdx-jsx@3.0.1: + resolution: {integrity: sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + monaco-editor@0.55.1: + resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + + mongodb-connection-string-url@3.0.2: + resolution: {integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==} + + mongodb@6.16.0: + resolution: {integrity: sha512-D1PNcdT0y4Grhou5Zi/qgipZOYeWrhLEpk33n3nm6LGtz61jvO88WlrWCK/bigMjpnOdAUKKQwsGIl0NtWMyYw==} + engines: {node: '>=16.20.1'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.188.0 + '@mongodb-js/zstd': ^1.1.0 || ^2.0.0 + gcp-metadata: ^5.2.0 + kerberos: ^2.0.1 + mongodb-client-encryption: '>=6.0.0 <7' + snappy: ^7.2.2 + socks: ^2.7.1 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + + mongoose-paginate-v2@1.8.5: + resolution: {integrity: sha512-kFxhot+yw9KmpAGSSrF/o+f00aC2uawgNUbhyaM0USS9L7dln1NA77/pLg4lgOaRgXMtfgCENamjqZwIM1Zrig==} + engines: {node: '>=4.0.0'} + + mongoose@8.15.1: + resolution: {integrity: sha512-RhQ4DzmBi5BNGcS0w4u1vdMRIKcteXTCNzDt1j7XRcdWYBz1MjMjulBhPaeC5jBCHOD1yinuOFTTSOWLLGexWw==} + engines: {node: '>=16.20.1'} + + mpath@0.9.0: + resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} + engines: {node: '>=4.0.0'} + + mquery@5.0.0: + resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==} + engines: {node: '>=14.0.0'} + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + next@15.4.9: + resolution: {integrity: sha512-/NedNmbiH4Umt/7SohT9VKxEdBt02Lj33xHrukE7d8Li6juT+75sEq4a4U06jggrvdbklKgr78OZEyWZ8XRrtw==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + nodemailer@7.0.9: + resolution: {integrity: sha512-9/Qm0qXIByEP8lEV2qOqcAW7bRpL8CR9jcTwk3NBnHJNmP9fIJ86g2fgmIXqHY+nj55ZEMwWqYAT2QTDpRUYiQ==} + engines: {node: '>=6.0.0'} + + nodemon@3.1.11: + resolution: {integrity: sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==} + engines: {node: '>=10'} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-to-formdata@4.5.1: + resolution: {integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==} + + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + payload@3.68.2: + resolution: {integrity: sha512-4ZdTJOUKSwUJXXMgEYIjonWmAgTxfnGTMuqQ1FZneSrZoZyjMOvXGiStEM0Ejd4zOlctUtAfum/gdgQC/CExyg==} + engines: {node: ^18.20.2 || >=20.9.0} + hasBin: true + peerDependencies: + graphql: ^16.8.1 + + peek-readable@5.4.2: + resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} + engines: {node: '>=14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-pretty@13.1.2: + resolution: {integrity: sha512-3cN0tCakkT4f3zo9RXDIhy6GTvtYD6bK4CRBLN9j3E/ePqN1tugAXD5rGVfoChW6s0hiek+eyYlLNqc/BG7vBQ==} + hasBin: true + + pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + + pino@9.14.0: + resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} + hasBin: true + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + engines: {node: '>=14'} + hasBin: true + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + pstree.remy@1.1.8: + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs-esm@7.0.2: + resolution: {integrity: sha512-D8NAthKSD7SGn748v+GLaaO6k08Mvpoqroa35PqIQC4gtUa8/Pb/k+r0m0NnGBVbHDP1gKZ2nVywqfMisRhV5A==} + engines: {node: '>=18'} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} + engines: {node: '>= 0.8'} + + react-datepicker@7.6.0: + resolution: {integrity: sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==} + peerDependencies: + react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + + react-dom@19.2.2: + resolution: {integrity: sha512-fhyD2BLrew6qYf4NNtHff1rLXvzR25rq49p+FeqByOazc6TcSi2n8EYulo5C1PbH+1uBW++5S1SG7FcUU6mlDg==} + peerDependencies: + react: ^19.2.2 + + react-error-boundary@3.1.4: + resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} + engines: {node: '>=10', npm: '>=6'} + peerDependencies: + react: '>=16.13.1' + + react-error-boundary@4.1.2: + resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} + peerDependencies: + react: '>=16.13.1' + + react-image-crop@10.1.8: + resolution: {integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==} + peerDependencies: + react: '>=16.13.1' + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-select@5.9.0: + resolution: {integrity: sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + + react@19.2.2: + resolution: {integrity: sha512-BdOGOY8OKRBcgoDkwqA8Q5XvOIhoNx/Sh6BnGJlet2Abt0X5BK0BDrqGyQgLhAVjD2nAg5f6o01u/OPUhG022Q==} + engines: {node: '>=0.10.0'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sanitize-filename@1.6.3: + resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + + sass@1.77.4: + resolution: {integrity: sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==} + engines: {node: '>=14.0.0'} + hasBin: true + + scheduler@0.25.0: + resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + scmp@2.1.0: + resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} + + secure-json-parse@4.1.0: + resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + + send@0.19.1: + resolution: {integrity: sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + sift@17.1.3: + resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + + simple-update-notifier@2.0.0: + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} + + simple-wcswidth@1.1.2: + resolution: {integrity: sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + sonic-boom@4.2.0: + resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + + sonner@1.7.4: + resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + stream-browserify@3.0.0: + resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + + strnum@2.1.1: + resolution: {integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==} + + strtok3@8.1.0: + resolution: {integrity: sha512-ExzDvHYPj6F6QkSNe/JxSlBxTh3OrI6wrAIz53ulxo1c4hBJ1bT9C/JrAthEKHWG9riVH3Xzg7B03Oxty6S2Lw==} + engines: {node: '>=16'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + token-types@6.1.1: + resolution: {integrity: sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ==} + engines: {node: '>=14.16'} + + touch@3.1.1: + resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} + hasBin: true + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + truncate-utf8-bytes@1.0.2: + resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + + ts-essentials@10.0.3: + resolution: {integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==} + peerDependencies: + typescript: '>=4.5.0' + peerDependenciesMeta: + typescript: + optional: true + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.20.3: + resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==} + engines: {node: '>=18.0.0'} + hasBin: true + + tsx@4.20.6: + resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + engines: {node: '>=18.0.0'} + hasBin: true + + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + undefsafe@2.0.5: + resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici@7.10.0: + resolution: {integrity: sha512-u5otvFBOBZvmdjWLVW+5DAc9Nkq8f24g0O9oY7qw2JVIF1VocIFoyz9JFkuVOS2j41AufeO0xnlweJ2RLT8nGw==} + engines: {node: '>=20.18.1'} + + unfetch@4.2.0: + resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + use-context-selector@2.0.0: + resolution: {integrity: sha512-owfuSmUNd3eNp3J9CdDl0kMgfidV+MkDvHPpvthN5ThqM+ibMccNE0k+Iq7TWC6JPFvGZqanqiGCuQx6DyV24g==} + peerDependencies: + react: '>=18.0.0' + scheduler: '>=0.19.0' + + use-isomorphic-layout-effect@1.2.1: + resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + utf8-byte-length@1.0.5: + resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xss@1.0.15: + resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==} + engines: {node: '>= 0.10.0'} + hasBin: true + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yjs@13.6.27: + resolution: {integrity: sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@apidevtools/json-schema-ref-parser@11.9.3': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.936.0 + tslib: 2.8.1 + + '@aws-crypto/crc32c@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.936.0 + tslib: 2.8.1 + + '@aws-crypto/sha1-browser@5.2.0': + dependencies: + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.936.0 + '@aws-sdk/util-locate-window': 3.893.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.936.0 + '@aws-sdk/util-locate-window': 3.893.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@1.2.2': + dependencies: + '@aws-crypto/util': 1.2.2 + '@aws-sdk/types': 3.936.0 + tslib: 1.14.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.936.0 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@1.2.2': + dependencies: + '@aws-sdk/types': 3.936.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-cognito-identity@3.948.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.947.0 + '@aws-sdk/credential-provider-node': 3.948.0 + '@aws-sdk/middleware-host-header': 3.936.0 + '@aws-sdk/middleware-logger': 3.936.0 + '@aws-sdk/middleware-recursion-detection': 3.948.0 + '@aws-sdk/middleware-user-agent': 3.947.0 + '@aws-sdk/region-config-resolver': 3.936.0 + '@aws-sdk/types': 3.936.0 + '@aws-sdk/util-endpoints': 3.936.0 + '@aws-sdk/util-user-agent-browser': 3.936.0 + '@aws-sdk/util-user-agent-node': 3.947.0 + '@smithy/config-resolver': 4.4.3 + '@smithy/core': 3.18.7 + '@smithy/fetch-http-handler': 5.3.6 + '@smithy/hash-node': 4.2.5 + '@smithy/invalid-dependency': 4.2.5 + '@smithy/middleware-content-length': 4.2.5 + '@smithy/middleware-endpoint': 4.3.14 + '@smithy/middleware-retry': 4.4.14 + '@smithy/middleware-serde': 4.2.6 + '@smithy/middleware-stack': 4.2.5 + '@smithy/node-config-provider': 4.3.5 + '@smithy/node-http-handler': 4.4.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/smithy-client': 4.9.10 + '@smithy/types': 4.9.0 + '@smithy/url-parser': 4.2.5 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.13 + '@smithy/util-defaults-mode-node': 4.2.16 + '@smithy/util-endpoints': 3.2.5 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-retry': 4.2.5 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-s3@3.948.0': + dependencies: + '@aws-crypto/sha1-browser': 5.2.0 + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.947.0 + '@aws-sdk/credential-provider-node': 3.948.0 + '@aws-sdk/middleware-bucket-endpoint': 3.936.0 + '@aws-sdk/middleware-expect-continue': 3.936.0 + '@aws-sdk/middleware-flexible-checksums': 3.947.0 + '@aws-sdk/middleware-host-header': 3.936.0 + '@aws-sdk/middleware-location-constraint': 3.936.0 + '@aws-sdk/middleware-logger': 3.936.0 + '@aws-sdk/middleware-recursion-detection': 3.948.0 + '@aws-sdk/middleware-sdk-s3': 3.947.0 + '@aws-sdk/middleware-ssec': 3.936.0 + '@aws-sdk/middleware-user-agent': 3.947.0 + '@aws-sdk/region-config-resolver': 3.936.0 + '@aws-sdk/signature-v4-multi-region': 3.947.0 + '@aws-sdk/types': 3.936.0 + '@aws-sdk/util-endpoints': 3.936.0 + '@aws-sdk/util-user-agent-browser': 3.936.0 + '@aws-sdk/util-user-agent-node': 3.947.0 + '@smithy/config-resolver': 4.4.3 + '@smithy/core': 3.18.7 + '@smithy/eventstream-serde-browser': 4.2.5 + '@smithy/eventstream-serde-config-resolver': 4.3.5 + '@smithy/eventstream-serde-node': 4.2.5 + '@smithy/fetch-http-handler': 5.3.6 + '@smithy/hash-blob-browser': 4.2.6 + '@smithy/hash-node': 4.2.5 + '@smithy/hash-stream-node': 4.2.5 + '@smithy/invalid-dependency': 4.2.5 + '@smithy/md5-js': 4.2.5 + '@smithy/middleware-content-length': 4.2.5 + '@smithy/middleware-endpoint': 4.3.14 + '@smithy/middleware-retry': 4.4.14 + '@smithy/middleware-serde': 4.2.6 + '@smithy/middleware-stack': 4.2.5 + '@smithy/node-config-provider': 4.3.5 + '@smithy/node-http-handler': 4.4.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/smithy-client': 4.9.10 + '@smithy/types': 4.9.0 + '@smithy/url-parser': 4.2.5 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.13 + '@smithy/util-defaults-mode-node': 4.2.16 + '@smithy/util-endpoints': 3.2.5 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-retry': 4.2.5 + '@smithy/util-stream': 4.5.6 + '@smithy/util-utf8': 4.2.0 + '@smithy/util-waiter': 4.2.5 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso@3.948.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.947.0 + '@aws-sdk/middleware-host-header': 3.936.0 + '@aws-sdk/middleware-logger': 3.936.0 + '@aws-sdk/middleware-recursion-detection': 3.948.0 + '@aws-sdk/middleware-user-agent': 3.947.0 + '@aws-sdk/region-config-resolver': 3.936.0 + '@aws-sdk/types': 3.936.0 + '@aws-sdk/util-endpoints': 3.936.0 + '@aws-sdk/util-user-agent-browser': 3.936.0 + '@aws-sdk/util-user-agent-node': 3.947.0 + '@smithy/config-resolver': 4.4.3 + '@smithy/core': 3.18.7 + '@smithy/fetch-http-handler': 5.3.6 + '@smithy/hash-node': 4.2.5 + '@smithy/invalid-dependency': 4.2.5 + '@smithy/middleware-content-length': 4.2.5 + '@smithy/middleware-endpoint': 4.3.14 + '@smithy/middleware-retry': 4.4.14 + '@smithy/middleware-serde': 4.2.6 + '@smithy/middleware-stack': 4.2.5 + '@smithy/node-config-provider': 4.3.5 + '@smithy/node-http-handler': 4.4.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/smithy-client': 4.9.10 + '@smithy/types': 4.9.0 + '@smithy/url-parser': 4.2.5 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.13 + '@smithy/util-defaults-mode-node': 4.2.16 + '@smithy/util-endpoints': 3.2.5 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-retry': 4.2.5 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/core@3.947.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@aws-sdk/xml-builder': 3.930.0 + '@smithy/core': 3.18.7 + '@smithy/node-config-provider': 4.3.5 + '@smithy/property-provider': 4.2.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/signature-v4': 5.3.5 + '@smithy/smithy-client': 4.9.10 + '@smithy/types': 4.9.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-cognito-identity@3.948.0': + dependencies: + '@aws-sdk/client-cognito-identity': 3.948.0 + '@aws-sdk/types': 3.936.0 + '@smithy/property-provider': 4.2.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-env@3.947.0': + dependencies: + '@aws-sdk/core': 3.947.0 + '@aws-sdk/types': 3.936.0 + '@smithy/property-provider': 4.2.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.947.0': + dependencies: + '@aws-sdk/core': 3.947.0 + '@aws-sdk/types': 3.936.0 + '@smithy/fetch-http-handler': 5.3.6 + '@smithy/node-http-handler': 4.4.5 + '@smithy/property-provider': 4.2.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/smithy-client': 4.9.10 + '@smithy/types': 4.9.0 + '@smithy/util-stream': 4.5.6 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.948.0': + dependencies: + '@aws-sdk/core': 3.947.0 + '@aws-sdk/credential-provider-env': 3.947.0 + '@aws-sdk/credential-provider-http': 3.947.0 + '@aws-sdk/credential-provider-login': 3.948.0 + '@aws-sdk/credential-provider-process': 3.947.0 + '@aws-sdk/credential-provider-sso': 3.948.0 + '@aws-sdk/credential-provider-web-identity': 3.948.0 + '@aws-sdk/nested-clients': 3.948.0 + '@aws-sdk/types': 3.936.0 + '@smithy/credential-provider-imds': 4.2.5 + '@smithy/property-provider': 4.2.5 + '@smithy/shared-ini-file-loader': 4.4.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-login@3.948.0': + dependencies: + '@aws-sdk/core': 3.947.0 + '@aws-sdk/nested-clients': 3.948.0 + '@aws-sdk/types': 3.936.0 + '@smithy/property-provider': 4.2.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/shared-ini-file-loader': 4.4.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-node@3.948.0': + dependencies: + '@aws-sdk/credential-provider-env': 3.947.0 + '@aws-sdk/credential-provider-http': 3.947.0 + '@aws-sdk/credential-provider-ini': 3.948.0 + '@aws-sdk/credential-provider-process': 3.947.0 + '@aws-sdk/credential-provider-sso': 3.948.0 + '@aws-sdk/credential-provider-web-identity': 3.948.0 + '@aws-sdk/types': 3.936.0 + '@smithy/credential-provider-imds': 4.2.5 + '@smithy/property-provider': 4.2.5 + '@smithy/shared-ini-file-loader': 4.4.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-process@3.947.0': + dependencies: + '@aws-sdk/core': 3.947.0 + '@aws-sdk/types': 3.936.0 + '@smithy/property-provider': 4.2.5 + '@smithy/shared-ini-file-loader': 4.4.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.948.0': + dependencies: + '@aws-sdk/client-sso': 3.948.0 + '@aws-sdk/core': 3.947.0 + '@aws-sdk/token-providers': 3.948.0 + '@aws-sdk/types': 3.936.0 + '@smithy/property-provider': 4.2.5 + '@smithy/shared-ini-file-loader': 4.4.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-web-identity@3.948.0': + dependencies: + '@aws-sdk/core': 3.947.0 + '@aws-sdk/nested-clients': 3.948.0 + '@aws-sdk/types': 3.936.0 + '@smithy/property-provider': 4.2.5 + '@smithy/shared-ini-file-loader': 4.4.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-providers@3.948.0': + dependencies: + '@aws-sdk/client-cognito-identity': 3.948.0 + '@aws-sdk/core': 3.947.0 + '@aws-sdk/credential-provider-cognito-identity': 3.948.0 + '@aws-sdk/credential-provider-env': 3.947.0 + '@aws-sdk/credential-provider-http': 3.947.0 + '@aws-sdk/credential-provider-ini': 3.948.0 + '@aws-sdk/credential-provider-login': 3.948.0 + '@aws-sdk/credential-provider-node': 3.948.0 + '@aws-sdk/credential-provider-process': 3.947.0 + '@aws-sdk/credential-provider-sso': 3.948.0 + '@aws-sdk/credential-provider-web-identity': 3.948.0 + '@aws-sdk/nested-clients': 3.948.0 + '@aws-sdk/types': 3.936.0 + '@smithy/config-resolver': 4.4.3 + '@smithy/core': 3.18.7 + '@smithy/credential-provider-imds': 4.2.5 + '@smithy/node-config-provider': 4.3.5 + '@smithy/property-provider': 4.2.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/lib-storage@3.948.0(@aws-sdk/client-s3@3.948.0)': + dependencies: + '@aws-sdk/client-s3': 3.948.0 + '@smithy/abort-controller': 4.2.5 + '@smithy/middleware-endpoint': 4.3.14 + '@smithy/smithy-client': 4.9.10 + buffer: 5.6.0 + events: 3.3.0 + stream-browserify: 3.0.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-bucket-endpoint@3.936.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@aws-sdk/util-arn-parser': 3.893.0 + '@smithy/node-config-provider': 4.3.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + '@smithy/util-config-provider': 4.2.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-expect-continue@3.936.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-flexible-checksums@3.947.0': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@aws-crypto/crc32c': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/core': 3.947.0 + '@aws-sdk/types': 3.936.0 + '@smithy/is-array-buffer': 4.2.0 + '@smithy/node-config-provider': 4.3.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-stream': 4.5.6 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-host-header@3.936.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-location-constraint@3.936.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.936.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.948.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@aws/lambda-invoke-store': 0.2.2 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-sdk-s3@3.947.0': + dependencies: + '@aws-sdk/core': 3.947.0 + '@aws-sdk/types': 3.936.0 + '@aws-sdk/util-arn-parser': 3.893.0 + '@smithy/core': 3.18.7 + '@smithy/node-config-provider': 4.3.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/signature-v4': 5.3.5 + '@smithy/smithy-client': 4.9.10 + '@smithy/types': 4.9.0 + '@smithy/util-config-provider': 4.2.0 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-stream': 4.5.6 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-ssec@3.936.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.947.0': + dependencies: + '@aws-sdk/core': 3.947.0 + '@aws-sdk/types': 3.936.0 + '@aws-sdk/util-endpoints': 3.936.0 + '@smithy/core': 3.18.7 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.948.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.947.0 + '@aws-sdk/middleware-host-header': 3.936.0 + '@aws-sdk/middleware-logger': 3.936.0 + '@aws-sdk/middleware-recursion-detection': 3.948.0 + '@aws-sdk/middleware-user-agent': 3.947.0 + '@aws-sdk/region-config-resolver': 3.936.0 + '@aws-sdk/types': 3.936.0 + '@aws-sdk/util-endpoints': 3.936.0 + '@aws-sdk/util-user-agent-browser': 3.936.0 + '@aws-sdk/util-user-agent-node': 3.947.0 + '@smithy/config-resolver': 4.4.3 + '@smithy/core': 3.18.7 + '@smithy/fetch-http-handler': 5.3.6 + '@smithy/hash-node': 4.2.5 + '@smithy/invalid-dependency': 4.2.5 + '@smithy/middleware-content-length': 4.2.5 + '@smithy/middleware-endpoint': 4.3.14 + '@smithy/middleware-retry': 4.4.14 + '@smithy/middleware-serde': 4.2.6 + '@smithy/middleware-stack': 4.2.5 + '@smithy/node-config-provider': 4.3.5 + '@smithy/node-http-handler': 4.4.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/smithy-client': 4.9.10 + '@smithy/types': 4.9.0 + '@smithy/url-parser': 4.2.5 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-body-length-node': 4.2.1 + '@smithy/util-defaults-mode-browser': 4.3.13 + '@smithy/util-defaults-mode-node': 4.2.16 + '@smithy/util-endpoints': 3.2.5 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-retry': 4.2.5 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/region-config-resolver@3.936.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/config-resolver': 4.4.3 + '@smithy/node-config-provider': 4.3.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.947.0': + dependencies: + '@aws-sdk/middleware-sdk-s3': 3.947.0 + '@aws-sdk/types': 3.936.0 + '@smithy/protocol-http': 5.3.5 + '@smithy/signature-v4': 5.3.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.948.0': + dependencies: + '@aws-sdk/core': 3.947.0 + '@aws-sdk/nested-clients': 3.948.0 + '@aws-sdk/types': 3.936.0 + '@smithy/property-provider': 4.2.5 + '@smithy/shared-ini-file-loader': 4.4.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/types@3.936.0': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/util-arn-parser@3.893.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.936.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/types': 4.9.0 + '@smithy/url-parser': 4.2.5 + '@smithy/util-endpoints': 3.2.5 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.893.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.936.0': + dependencies: + '@aws-sdk/types': 3.936.0 + '@smithy/types': 4.9.0 + bowser: 2.13.1 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.947.0': + dependencies: + '@aws-sdk/middleware-user-agent': 3.947.0 + '@aws-sdk/types': 3.936.0 + '@smithy/node-config-provider': 4.3.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@aws-sdk/util-utf8-browser@3.259.0': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.930.0': + dependencies: + '@smithy/types': 4.9.0 + fast-xml-parser: 5.2.5 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.2': {} + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@borewit/text-codec@0.1.1': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@date-fns/tz@1.2.0': {} + + '@dnd-kit/accessibility@3.1.1(react@19.2.2)': + dependencies: + react: 19.2.2 + tslib: 2.8.1 + + '@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@dnd-kit/accessibility': 3.1.1(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + tslib: 2.8.1 + + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + tslib: 2.8.1 + + '@dnd-kit/utilities@3.2.2(react@19.2.2)': + dependencies: + react: 19.2.2 + tslib: 2.8.1 + + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.27.1 + '@babel/runtime': 7.28.4 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/hash@0.9.2': {} + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.2)': + dependencies: + '@babel/runtime': 7.28.4 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.2) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.2 + optionalDependencies: + '@types/react': 19.2.1 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.2.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.2)': + dependencies: + react: 19.2.2 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/aix-ppc64@0.27.1': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.27.1': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-arm@0.27.1': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/android-x64@0.27.1': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.27.1': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.27.1': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.27.1': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.27.1': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.27.1': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-arm@0.27.1': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.27.1': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.27.1': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.27.1': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.27.1': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.27.1': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.27.1': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/linux-x64@0.27.1': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.27.1': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.27.1': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.27.1': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.27.1': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.27.1': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.27.1': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.27.1': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.27.1': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@esbuild/win32-x64@0.27.1': + optional: true + + '@faceless-ui/modal@3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + body-scroll-lock: 4.0.0-beta.0 + focus-trap: 7.5.4 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + + '@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@faceless-ui/window-info@3.0.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@floating-ui/react@0.27.16(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@floating-ui/utils': 0.2.10 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + tabbable: 6.3.0 + + '@floating-ui/utils@0.2.10': {} + + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.7.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jsdevtools/ono@7.1.3': {} + + '@lexical/clipboard@0.35.0': + dependencies: + '@lexical/html': 0.35.0 + '@lexical/list': 0.35.0 + '@lexical/selection': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/code@0.35.0': + dependencies: + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + prismjs: 1.30.0 + + '@lexical/devtools-core@0.35.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@lexical/html': 0.35.0 + '@lexical/link': 0.35.0 + '@lexical/mark': 0.35.0 + '@lexical/table': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@lexical/dragon@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/hashtag@0.35.0': + dependencies: + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/headless@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/history@0.35.0': + dependencies: + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/html@0.35.0': + dependencies: + '@lexical/selection': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/link@0.35.0': + dependencies: + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/list@0.35.0': + dependencies: + '@lexical/selection': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/mark@0.35.0': + dependencies: + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/markdown@0.35.0': + dependencies: + '@lexical/code': 0.35.0 + '@lexical/link': 0.35.0 + '@lexical/list': 0.35.0 + '@lexical/rich-text': 0.35.0 + '@lexical/text': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/offset@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/overflow@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/plain-text@0.35.0': + dependencies: + '@lexical/clipboard': 0.35.0 + '@lexical/selection': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/react@0.35.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.27)': + dependencies: + '@floating-ui/react': 0.27.16(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@lexical/devtools-core': 0.35.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@lexical/dragon': 0.35.0 + '@lexical/hashtag': 0.35.0 + '@lexical/history': 0.35.0 + '@lexical/link': 0.35.0 + '@lexical/list': 0.35.0 + '@lexical/mark': 0.35.0 + '@lexical/markdown': 0.35.0 + '@lexical/overflow': 0.35.0 + '@lexical/plain-text': 0.35.0 + '@lexical/rich-text': 0.35.0 + '@lexical/table': 0.35.0 + '@lexical/text': 0.35.0 + '@lexical/utils': 0.35.0 + '@lexical/yjs': 0.35.0(yjs@13.6.27) + lexical: 0.35.0 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 3.1.4(react@19.2.2) + transitivePeerDependencies: + - yjs + + '@lexical/rich-text@0.35.0': + dependencies: + '@lexical/clipboard': 0.35.0 + '@lexical/selection': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/selection@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/table@0.35.0': + dependencies: + '@lexical/clipboard': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/text@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/utils@0.35.0': + dependencies: + '@lexical/list': 0.35.0 + '@lexical/selection': 0.35.0 + '@lexical/table': 0.35.0 + lexical: 0.35.0 + + '@lexical/yjs@0.35.0(yjs@13.6.27)': + dependencies: + '@lexical/offset': 0.35.0 + '@lexical/selection': 0.35.0 + lexical: 0.35.0 + yjs: 13.6.27 + + '@monaco-editor/loader@1.7.0': + dependencies: + state-local: 1.0.7 + + '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@monaco-editor/loader': 1.7.0 + monaco-editor: 0.55.1 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@mongodb-js/saslprep@1.4.0': + dependencies: + sparse-bitfield: 3.0.3 + + '@next/env@15.4.9': {} + + '@next/env@15.5.8': {} + + '@next/swc-darwin-arm64@15.4.8': + optional: true + + '@next/swc-darwin-x64@15.4.8': + optional: true + + '@next/swc-linux-arm64-gnu@15.4.8': + optional: true + + '@next/swc-linux-arm64-musl@15.4.8': + optional: true + + '@next/swc-linux-x64-gnu@15.4.8': + optional: true + + '@next/swc-linux-x64-musl@15.4.8': + optional: true + + '@next/swc-win32-arm64-msvc@15.4.8': + optional: true + + '@next/swc-win32-x64-msvc@15.4.8': + optional: true + + '@payloadcms/db-mongodb@3.68.2(@aws-sdk/credential-providers@3.948.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))': + dependencies: + mongoose: 8.15.1(@aws-sdk/credential-providers@3.948.0) + mongoose-paginate-v2: 1.8.5 + payload: 3.68.2(graphql@16.12.0)(typescript@5.9.3) + prompts: 2.4.2 + uuid: 10.0.0 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + - supports-color + + '@payloadcms/email-nodemailer@3.68.2(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))': + dependencies: + nodemailer: 7.0.9 + payload: 3.68.2(graphql@16.12.0)(typescript@5.9.3) + + '@payloadcms/graphql@3.68.2(graphql@16.12.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(typescript@5.9.3)': + dependencies: + graphql: 16.12.0 + graphql-scalars: 1.22.2(graphql@16.12.0) + payload: 3.68.2(graphql@16.12.0)(typescript@5.9.3) + pluralize: 8.0.0 + ts-essentials: 10.0.3(typescript@5.9.3) + tsx: 4.20.6 + transitivePeerDependencies: + - typescript + + '@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@payloadcms/graphql': 3.68.2(graphql@16.12.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(typescript@5.9.3) + '@payloadcms/translations': 3.68.2 + '@payloadcms/ui': 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + busboy: 1.6.0 + dequal: 2.0.3 + file-type: 19.3.0 + graphql: 16.12.0 + graphql-http: 1.22.4(graphql@16.12.0) + graphql-playground-html: 1.6.30 + http-status: 2.1.0 + next: 15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + path-to-regexp: 6.3.0 + payload: 3.68.2(graphql@16.12.0)(typescript@5.9.3) + qs-esm: 7.0.2 + sass: 1.77.4 + uuid: 10.0.0 + transitivePeerDependencies: + - '@types/react' + - monaco-editor + - react + - react-dom + - supports-color + - typescript + + '@payloadcms/payload-cloud@3.68.2(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))': + dependencies: + '@aws-sdk/client-cognito-identity': 3.948.0 + '@aws-sdk/client-s3': 3.948.0 + '@aws-sdk/credential-providers': 3.948.0 + '@aws-sdk/lib-storage': 3.948.0(@aws-sdk/client-s3@3.948.0) + '@payloadcms/email-nodemailer': 3.68.2(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3)) + amazon-cognito-identity-js: 6.3.16 + nodemailer: 7.0.9 + payload: 3.68.2(graphql@16.12.0)(typescript@5.9.3) + transitivePeerDependencies: + - aws-crt + - encoding + + '@payloadcms/richtext-lexical@3.68.2(@faceless-ui/modal@3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)(yjs@13.6.27)': + dependencies: + '@faceless-ui/modal': 3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@lexical/clipboard': 0.35.0 + '@lexical/headless': 0.35.0 + '@lexical/html': 0.35.0 + '@lexical/link': 0.35.0 + '@lexical/list': 0.35.0 + '@lexical/mark': 0.35.0 + '@lexical/react': 0.35.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.27) + '@lexical/rich-text': 0.35.0 + '@lexical/selection': 0.35.0 + '@lexical/table': 0.35.0 + '@lexical/utils': 0.35.0 + '@payloadcms/next': 3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + '@payloadcms/translations': 3.68.2 + '@payloadcms/ui': 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + '@types/uuid': 10.0.0 + acorn: 8.12.1 + bson-objectid: 2.0.4 + csstype: 3.1.3 + dequal: 2.0.3 + escape-html: 1.0.3 + jsox: 1.2.121 + lexical: 0.35.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-mdx-jsx: 3.1.3 + micromark-extension-mdx-jsx: 3.0.1 + payload: 3.68.2(graphql@16.12.0)(typescript@5.9.3) + qs-esm: 7.0.2 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 4.1.2(react@19.2.2) + ts-essentials: 10.0.3(typescript@5.9.3) + uuid: 10.0.0 + transitivePeerDependencies: + - '@types/react' + - monaco-editor + - next + - supports-color + - typescript + - yjs + + '@payloadcms/translations@3.68.2': + dependencies: + date-fns: 4.1.0 + + '@payloadcms/ui@3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)': + dependencies: + '@date-fns/tz': 1.2.0 + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + '@faceless-ui/modal': 3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/window-info': 3.0.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@monaco-editor/react': 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@payloadcms/translations': 3.68.2 + bson-objectid: 2.0.4 + date-fns: 4.1.0 + dequal: 2.0.3 + md5: 2.3.0 + next: 15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + object-to-formdata: 4.5.1 + payload: 3.68.2(graphql@16.12.0)(typescript@5.9.3) + qs-esm: 7.0.2 + react: 19.2.2 + react-datepicker: 7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-dom: 19.2.2(react@19.2.2) + react-image-crop: 10.1.8(react@19.2.2) + react-select: 5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + scheduler: 0.25.0 + sonner: 1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + ts-essentials: 10.0.3(typescript@5.9.3) + use-context-selector: 2.0.0(react@19.2.2)(scheduler@0.25.0) + uuid: 10.0.0 + transitivePeerDependencies: + - '@types/react' + - monaco-editor + - supports-color + - typescript + + '@pinojs/redact@0.4.0': {} + + '@smithy/abort-controller@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/chunked-blob-reader-native@4.2.1': + dependencies: + '@smithy/util-base64': 4.3.0 + tslib: 2.8.1 + + '@smithy/chunked-blob-reader@5.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/config-resolver@4.4.3': + dependencies: + '@smithy/node-config-provider': 4.3.5 + '@smithy/types': 4.9.0 + '@smithy/util-config-provider': 4.2.0 + '@smithy/util-endpoints': 3.2.5 + '@smithy/util-middleware': 4.2.5 + tslib: 2.8.1 + + '@smithy/core@3.18.7': + dependencies: + '@smithy/middleware-serde': 4.2.6 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-body-length-browser': 4.2.0 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-stream': 4.5.6 + '@smithy/util-utf8': 4.2.0 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.2.5': + dependencies: + '@smithy/node-config-provider': 4.3.5 + '@smithy/property-provider': 4.2.5 + '@smithy/types': 4.9.0 + '@smithy/url-parser': 4.2.5 + tslib: 2.8.1 + + '@smithy/eventstream-codec@4.2.5': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.9.0 + '@smithy/util-hex-encoding': 4.2.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-browser@4.2.5': + dependencies: + '@smithy/eventstream-serde-universal': 4.2.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-config-resolver@4.3.5': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-node@4.2.5': + dependencies: + '@smithy/eventstream-serde-universal': 4.2.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-universal@4.2.5': + dependencies: + '@smithy/eventstream-codec': 4.2.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.3.6': + dependencies: + '@smithy/protocol-http': 5.3.5 + '@smithy/querystring-builder': 4.2.5 + '@smithy/types': 4.9.0 + '@smithy/util-base64': 4.3.0 + tslib: 2.8.1 + + '@smithy/hash-blob-browser@4.2.6': + dependencies: + '@smithy/chunked-blob-reader': 5.2.0 + '@smithy/chunked-blob-reader-native': 4.2.1 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/hash-node@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + '@smithy/util-buffer-from': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/hash-stream-node@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/invalid-dependency@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/is-array-buffer@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/md5-js@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/middleware-content-length@4.2.5': + dependencies: + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@4.3.14': + dependencies: + '@smithy/core': 3.18.7 + '@smithy/middleware-serde': 4.2.6 + '@smithy/node-config-provider': 4.3.5 + '@smithy/shared-ini-file-loader': 4.4.0 + '@smithy/types': 4.9.0 + '@smithy/url-parser': 4.2.5 + '@smithy/util-middleware': 4.2.5 + tslib: 2.8.1 + + '@smithy/middleware-retry@4.4.14': + dependencies: + '@smithy/node-config-provider': 4.3.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/service-error-classification': 4.2.5 + '@smithy/smithy-client': 4.9.10 + '@smithy/types': 4.9.0 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-retry': 4.2.5 + '@smithy/uuid': 1.1.0 + tslib: 2.8.1 + + '@smithy/middleware-serde@4.2.6': + dependencies: + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/middleware-stack@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/node-config-provider@4.3.5': + dependencies: + '@smithy/property-provider': 4.2.5 + '@smithy/shared-ini-file-loader': 4.4.0 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.4.5': + dependencies: + '@smithy/abort-controller': 4.2.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/querystring-builder': 4.2.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/property-provider@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/protocol-http@5.3.5': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/querystring-builder@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + '@smithy/util-uri-escape': 4.2.0 + tslib: 2.8.1 + + '@smithy/querystring-parser@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/service-error-classification@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + + '@smithy/shared-ini-file-loader@4.4.0': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.3.5': + dependencies: + '@smithy/is-array-buffer': 4.2.0 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + '@smithy/util-hex-encoding': 4.2.0 + '@smithy/util-middleware': 4.2.5 + '@smithy/util-uri-escape': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/smithy-client@4.9.10': + dependencies: + '@smithy/core': 3.18.7 + '@smithy/middleware-endpoint': 4.3.14 + '@smithy/middleware-stack': 4.2.5 + '@smithy/protocol-http': 5.3.5 + '@smithy/types': 4.9.0 + '@smithy/util-stream': 4.5.6 + tslib: 2.8.1 + + '@smithy/types@4.9.0': + dependencies: + tslib: 2.8.1 + + '@smithy/url-parser@4.2.5': + dependencies: + '@smithy/querystring-parser': 4.2.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/util-base64@4.3.0': + dependencies: + '@smithy/util-buffer-from': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/util-body-length-browser@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@4.2.1': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-buffer-from@4.2.0': + dependencies: + '@smithy/is-array-buffer': 4.2.0 + tslib: 2.8.1 + + '@smithy/util-config-provider@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-defaults-mode-browser@4.3.13': + dependencies: + '@smithy/property-provider': 4.2.5 + '@smithy/smithy-client': 4.9.10 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@4.2.16': + dependencies: + '@smithy/config-resolver': 4.4.3 + '@smithy/credential-provider-imds': 4.2.5 + '@smithy/node-config-provider': 4.3.5 + '@smithy/property-provider': 4.2.5 + '@smithy/smithy-client': 4.9.10 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/util-endpoints@3.2.5': + dependencies: + '@smithy/node-config-provider': 4.3.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/util-hex-encoding@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-middleware@4.2.5': + dependencies: + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/util-retry@4.2.5': + dependencies: + '@smithy/service-error-classification': 4.2.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/util-stream@4.5.6': + dependencies: + '@smithy/fetch-http-handler': 5.3.6 + '@smithy/node-http-handler': 4.4.5 + '@smithy/types': 4.9.0 + '@smithy/util-base64': 4.3.0 + '@smithy/util-buffer-from': 4.2.0 + '@smithy/util-hex-encoding': 4.2.0 + '@smithy/util-utf8': 4.2.0 + tslib: 2.8.1 + + '@smithy/util-uri-escape@4.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@4.2.0': + dependencies: + '@smithy/util-buffer-from': 4.2.0 + tslib: 2.8.1 + + '@smithy/util-waiter@4.2.5': + dependencies: + '@smithy/abort-controller': 4.2.5 + '@smithy/types': 4.9.0 + tslib: 2.8.1 + + '@smithy/uuid@1.1.0': + dependencies: + tslib: 2.8.1 + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tokenizer/token@0.3.0': {} + + '@tsconfig/node10@1.0.12': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/acorn@4.0.6': + dependencies: + '@types/estree': 1.0.8 + + '@types/body-parser@1.19.6': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 18.19.130 + + '@types/busboy@1.5.4': + dependencies: + '@types/node': 18.19.130 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 18.19.130 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + + '@types/estree@1.0.8': {} + + '@types/express-serve-static-core@5.1.0': + dependencies: + '@types/node': 18.19.130 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + '@types/send': 1.2.1 + + '@types/express@5.0.6': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 5.1.0 + '@types/serve-static': 2.2.0 + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/http-errors@2.0.5': {} + + '@types/json-schema@7.0.15': {} + + '@types/lodash@4.17.21': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@18.19.130': + dependencies: + undici-types: 5.26.5 + + '@types/parse-json@4.0.2': {} + + '@types/qs@6.14.0': {} + + '@types/range-parser@1.2.7': {} + + '@types/react-dom@19.2.1(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 + + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 + + '@types/react@19.2.1': + dependencies: + csstype: 3.2.3 + + '@types/send@1.2.1': + dependencies: + '@types/node': 18.19.130 + + '@types/serve-static@2.2.0': + dependencies: + '@types/http-errors': 2.0.5 + '@types/node': 18.19.130 + + '@types/trusted-types@2.0.7': + optional: true + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@types/uuid@10.0.0': {} + + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@11.0.5': + dependencies: + '@types/webidl-conversions': 7.0.3 + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.15.0 + + acorn@8.12.1: {} + + acorn@8.15.0: {} + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + amazon-cognito-identity-js@6.3.16: + dependencies: + '@aws-crypto/sha256-js': 1.2.2 + buffer: 4.9.2 + fast-base64-decode: 1.0.0 + isomorphic-unfetch: 3.1.0 + js-cookie: 2.2.1 + transitivePeerDependencies: + - encoding + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@4.1.3: {} + + argparse@2.0.1: {} + + array-flatten@1.1.1: {} + + atomic-sleep@1.0.0: {} + + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.28.4 + cosmiconfig: 7.1.0 + resolve: 1.22.11 + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + binary-extensions@2.3.0: {} + + body-parser@1.20.4: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 2.5.3 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + body-scroll-lock@4.0.0-beta.0: {} + + bowser@2.13.1: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + bson-objectid@2.0.4: {} + + bson@6.10.4: {} + + buffer@4.9.2: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + isarray: 1.0.0 + + buffer@5.6.0: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001760: {} + + ccount@2.0.1: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + charenc@0.0.2: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + ci-info@4.3.1: {} + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + colorette@2.0.20: {} + + commander@2.20.3: {} + + concat-map@0.0.1: {} + + console-table-printer@2.12.1: + dependencies: + simple-wcswidth: 1.1.2 + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + convert-source-map@1.9.0: {} + + cookie-signature@1.0.7: {} + + cookie@0.7.2: {} + + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.1 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + + create-require@1.1.1: {} + + croner@9.1.0: {} + + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crypt@0.0.2: {} + + cssfilter@0.0.10: {} + + csstype@3.1.3: {} + + csstype@3.2.3: {} + + dataloader@2.2.3: {} + + date-fns@3.6.0: {} + + date-fns@4.1.0: {} + + dateformat@4.6.3: {} + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@4.4.3(supports-color@5.5.0): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 5.5.0 + + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + + deepmerge@4.3.1: {} + + depd@2.0.0: {} + + dequal@2.0.3: {} + + destroy@1.2.0: {} + + detect-libc@2.1.2: + optional: true + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff@4.0.2: {} + + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.28.4 + csstype: 3.2.3 + + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + encodeurl@1.0.2: {} + + encodeurl@2.0.0: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + esbuild@0.27.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.1 + '@esbuild/android-arm': 0.27.1 + '@esbuild/android-arm64': 0.27.1 + '@esbuild/android-x64': 0.27.1 + '@esbuild/darwin-arm64': 0.27.1 + '@esbuild/darwin-x64': 0.27.1 + '@esbuild/freebsd-arm64': 0.27.1 + '@esbuild/freebsd-x64': 0.27.1 + '@esbuild/linux-arm': 0.27.1 + '@esbuild/linux-arm64': 0.27.1 + '@esbuild/linux-ia32': 0.27.1 + '@esbuild/linux-loong64': 0.27.1 + '@esbuild/linux-mips64el': 0.27.1 + '@esbuild/linux-ppc64': 0.27.1 + '@esbuild/linux-riscv64': 0.27.1 + '@esbuild/linux-s390x': 0.27.1 + '@esbuild/linux-x64': 0.27.1 + '@esbuild/netbsd-arm64': 0.27.1 + '@esbuild/netbsd-x64': 0.27.1 + '@esbuild/openbsd-arm64': 0.27.1 + '@esbuild/openbsd-x64': 0.27.1 + '@esbuild/openharmony-arm64': 0.27.1 + '@esbuild/sunos-x64': 0.27.1 + '@esbuild/win32-arm64': 0.27.1 + '@esbuild/win32-ia32': 0.27.1 + '@esbuild/win32-x64': 0.27.1 + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + etag@1.8.1: {} + + events@3.3.0: {} + + express@4.22.1: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.4 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.0.7 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.2 + fresh: 0.5.2 + http-errors: 2.0.1 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.12 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.1 + serve-static: 1.16.2 + setprototypeof: 1.2.0 + statuses: 2.0.2 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fast-base64-decode@1.0.0: {} + + fast-copy@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-safe-stringify@2.1.1: {} + + fast-uri@3.1.0: {} + + fast-xml-parser@5.2.5: + dependencies: + strnum: 2.1.1 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-type@19.3.0: + dependencies: + strtok3: 8.1.0 + token-types: 6.1.1 + uint8array-extras: 1.5.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@1.3.2: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + find-root@1.1.0: {} + + focus-trap@7.5.4: + dependencies: + tabbable: 6.3.0 + + forwarded@0.2.0: {} + + fresh@0.5.2: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + get-tsconfig@4.8.1: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + gopd@1.2.0: {} + + graphql-http@1.22.4(graphql@16.12.0): + dependencies: + graphql: 16.12.0 + + graphql-playground-html@1.6.30: + dependencies: + xss: 1.0.15 + + graphql-scalars@1.22.2(graphql@16.12.0): + dependencies: + graphql: 16.12.0 + tslib: 2.8.1 + + graphql@16.12.0: {} + + has-flag@3.0.0: {} + + has-symbols@1.1.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + help-me@5.0.0: {} + + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + http-status@2.1.0: {} + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore-by-default@1.0.1: {} + + image-size@2.0.2: {} + + immutable@4.3.7: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + inherits@2.0.4: {} + + ipaddr.js@1.9.1: {} + + ipaddr.js@2.2.0: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-arrayish@0.2.1: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-buffer@1.1.6: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-decimal@2.0.1: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-number@7.0.0: {} + + isarray@1.0.0: {} + + isexe@2.0.0: {} + + isomorphic-unfetch@3.1.0: + dependencies: + node-fetch: 2.7.0 + unfetch: 4.2.0 + transitivePeerDependencies: + - encoding + + isomorphic.js@0.2.5: {} + + jose@5.9.6: {} + + joycon@3.1.1: {} + + js-cookie@2.2.1: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-to-typescript@15.0.3: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.9.3 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.21 + is-glob: 4.0.3 + js-yaml: 4.1.1 + lodash: 4.17.21 + minimist: 1.2.8 + prettier: 3.7.4 + tinyglobby: 0.2.15 + + json-schema-traverse@1.0.0: {} + + jsox@1.2.121: {} + + kareem@2.6.3: {} + + kleur@3.0.3: {} + + lexical@0.35.0: {} + + lib0@0.2.114: + dependencies: + isomorphic.js: 0.2.5 + + lines-and-columns@1.2.4: {} + + lodash@4.17.21: {} + + longest-streak@3.1.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + make-error@1.3.6: {} + + marked@14.0.0: {} + + math-intrinsics@1.1.0: {} + + md5@2.3.0: + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.1.3: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + media-typer@0.3.0: {} + + memoize-one@6.0.0: {} + + memory-pager@1.5.0: {} + + merge-descriptors@1.0.3: {} + + methods@1.1.2: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.1: + dependencies: + '@types/acorn': 4.0.6 + '@types/estree': 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3(supports-color@5.5.0) + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimist@1.2.8: {} + + monaco-editor@0.55.1: + dependencies: + dompurify: 3.2.7 + marked: 14.0.0 + + mongodb-connection-string-url@3.0.2: + dependencies: + '@types/whatwg-url': 11.0.5 + whatwg-url: 14.2.0 + + mongodb@6.16.0(@aws-sdk/credential-providers@3.948.0): + dependencies: + '@mongodb-js/saslprep': 1.4.0 + bson: 6.10.4 + mongodb-connection-string-url: 3.0.2 + optionalDependencies: + '@aws-sdk/credential-providers': 3.948.0 + + mongoose-paginate-v2@1.8.5: {} + + mongoose@8.15.1(@aws-sdk/credential-providers@3.948.0): + dependencies: + bson: 6.10.4 + kareem: 2.6.3 + mongodb: 6.16.0(@aws-sdk/credential-providers@3.948.0) + mpath: 0.9.0 + mquery: 5.0.0 + ms: 2.1.3 + sift: 17.1.3 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + - supports-color + + mpath@0.9.0: {} + + mquery@5.0.0: + dependencies: + debug: 4.4.3(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color + + ms@2.0.0: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + negotiator@0.6.3: {} + + next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): + dependencies: + '@next/env': 15.4.9 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001760 + postcss: 8.4.31 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + styled-jsx: 5.1.6(react@19.2.2) + optionalDependencies: + '@next/swc-darwin-arm64': 15.4.8 + '@next/swc-darwin-x64': 15.4.8 + '@next/swc-linux-arm64-gnu': 15.4.8 + '@next/swc-linux-arm64-musl': 15.4.8 + '@next/swc-linux-x64-gnu': 15.4.8 + '@next/swc-linux-x64-musl': 15.4.8 + '@next/swc-win32-arm64-msvc': 15.4.8 + '@next/swc-win32-x64-msvc': 15.4.8 + sass: 1.77.4 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + nodemailer@7.0.9: {} + + nodemon@3.1.11: + dependencies: + chokidar: 3.6.0 + debug: 4.4.3(supports-color@5.5.0) + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 7.7.3 + simple-update-notifier: 2.0.0 + supports-color: 5.5.0 + touch: 3.1.1 + undefsafe: 2.0.5 + + normalize-path@3.0.0: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-to-formdata@4.5.1: {} + + on-exit-leak-free@2.1.2: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.2.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parseurl@1.3.3: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-to-regexp@0.1.12: {} + + path-to-regexp@6.3.0: {} + + path-type@4.0.0: {} + + payload@3.68.2(graphql@16.12.0)(typescript@5.9.3): + dependencies: + '@next/env': 15.5.8 + '@payloadcms/translations': 3.68.2 + '@types/busboy': 1.5.4 + ajv: 8.17.1 + bson-objectid: 2.0.4 + busboy: 1.6.0 + ci-info: 4.3.1 + console-table-printer: 2.12.1 + croner: 9.1.0 + dataloader: 2.2.3 + deepmerge: 4.3.1 + file-type: 19.3.0 + get-tsconfig: 4.8.1 + graphql: 16.12.0 + http-status: 2.1.0 + image-size: 2.0.2 + ipaddr.js: 2.2.0 + jose: 5.9.6 + json-schema-to-typescript: 15.0.3 + minimist: 1.2.8 + path-to-regexp: 6.3.0 + pino: 9.14.0 + pino-pretty: 13.1.2 + pluralize: 8.0.0 + qs-esm: 7.0.2 + sanitize-filename: 1.6.3 + scmp: 2.1.0 + ts-essentials: 10.0.3(typescript@5.9.3) + tsx: 4.20.3 + undici: 7.10.0 + uuid: 10.0.0 + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + + peek-readable@5.4.2: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-pretty@13.1.2: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pump: 3.0.3 + secure-json-parse: 4.1.0 + sonic-boom: 4.2.0 + strip-json-comments: 5.0.3 + + pino-std-serializers@7.0.0: {} + + pino@9.14.0: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + + pluralize@8.0.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.7.4: {} + + prismjs@1.30.0: {} + + process-warning@5.0.0: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + pstree.remy@1.1.8: {} + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + qs-esm@7.0.2: {} + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + quick-format-unescaped@4.0.4: {} + + range-parser@1.2.1: {} + + raw-body@2.5.3: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + react-datepicker@7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): + dependencies: + '@floating-ui/react': 0.27.16(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + clsx: 2.1.1 + date-fns: 3.6.0 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + react-dom@19.2.2(react@19.2.2): + dependencies: + react: 19.2.2 + scheduler: 0.27.0 + + react-error-boundary@3.1.4(react@19.2.2): + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.2 + + react-error-boundary@4.1.2(react@19.2.2): + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.2 + + react-image-crop@10.1.8(react@19.2.2): + dependencies: + react: 19.2.2 + + react-is@16.13.1: {} + + react-select@5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): + dependencies: + '@babel/runtime': 7.28.4 + '@emotion/cache': 11.14.0 + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.2) + '@floating-ui/dom': 1.7.4 + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) + memoize-one: 6.0.0 + prop-types: 15.8.1 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.1)(react@19.2.2) + transitivePeerDependencies: + - '@types/react' + - supports-color + + react-transition-group@4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2): + dependencies: + '@babel/runtime': 7.28.4 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + react@19.2.2: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + real-require@0.2.0: {} + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + safe-buffer@5.2.1: {} + + safe-stable-stringify@2.5.0: {} + + safer-buffer@2.1.2: {} + + sanitize-filename@1.6.3: + dependencies: + truncate-utf8-bytes: 1.0.2 + + sass@1.77.4: + dependencies: + chokidar: 3.6.0 + immutable: 4.3.7 + source-map-js: 1.2.1 + + scheduler@0.25.0: {} + + scheduler@0.27.0: {} + + scmp@2.1.0: {} + + secure-json-parse@4.1.0: {} + + semver@7.7.3: {} + + send@0.19.0: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + send@0.19.1: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + sift@17.1.3: {} + + simple-update-notifier@2.0.0: + dependencies: + semver: 7.7.3 + + simple-wcswidth@1.1.2: {} + + sisteransi@1.0.5: {} + + sonic-boom@4.2.0: + dependencies: + atomic-sleep: 1.0.0 + + sonner@1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2): + dependencies: + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + source-map-js@1.2.1: {} + + source-map@0.5.7: {} + + sparse-bitfield@3.0.3: + dependencies: + memory-pager: 1.5.0 + + split2@4.2.0: {} + + state-local@1.0.7: {} + + statuses@2.0.1: {} + + statuses@2.0.2: {} + + stream-browserify@3.0.0: + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + + streamsearch@1.1.0: {} + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-json-comments@5.0.3: {} + + strnum@2.1.1: {} + + strtok3@8.1.0: + dependencies: + '@tokenizer/token': 0.3.0 + peek-readable: 5.4.2 + + styled-jsx@5.1.6(react@19.2.2): + dependencies: + client-only: 0.0.1 + react: 19.2.2 + + stylis@4.2.0: {} + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tabbable@6.3.0: {} + + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + token-types@6.1.1: + dependencies: + '@borewit/text-codec': 0.1.1 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + touch@3.1.1: {} + + tr46@0.0.3: {} + + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + + truncate-utf8-bytes@1.0.2: + dependencies: + utf8-byte-length: 1.0.5 + + ts-essentials@10.0.3(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + + ts-node@10.9.2(@types/node@18.19.130)(typescript@5.9.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.12 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 18.19.130 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.9.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tslib@1.14.1: {} + + tslib@2.8.1: {} + + tsx@4.20.3: + dependencies: + esbuild: 0.25.12 + get-tsconfig: 4.8.1 + optionalDependencies: + fsevents: 2.3.3 + + tsx@4.20.6: + dependencies: + esbuild: 0.25.12 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + + tsx@4.21.0: + dependencies: + esbuild: 0.27.1 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + typescript@5.9.3: {} + + uint8array-extras@1.5.0: {} + + undefsafe@2.0.5: {} + + undici-types@5.26.5: {} + + undici@7.10.0: {} + + unfetch@4.2.0: {} + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unpipe@1.0.0: {} + + use-context-selector@2.0.0(react@19.2.2)(scheduler@0.25.0): + dependencies: + react: 19.2.2 + scheduler: 0.25.0 + + use-isomorphic-layout-effect@1.2.1(@types/react@19.2.1)(react@19.2.2): + dependencies: + react: 19.2.2 + optionalDependencies: + '@types/react': 19.2.1 + + utf8-byte-length@1.0.5: {} + + util-deprecate@1.0.2: {} + + utils-merge@1.0.1: {} + + uuid@10.0.0: {} + + v8-compile-cache-lib@3.0.1: {} + + vary@1.1.2: {} + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + webidl-conversions@3.0.1: {} + + webidl-conversions@7.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrappy@1.0.2: {} + + ws@8.18.3: {} + + xss@1.0.15: + dependencies: + commander: 2.20.3 + cssfilter: 0.0.10 + + yaml@1.10.2: {} + + yjs@13.6.27: + dependencies: + lib0: 0.2.114 + + yn@3.1.1: {} + + zwitch@2.0.4: {} diff --git a/examples/draft-preview/package.json b/examples/draft-preview/package.json index 00c6a5cfb83..7651748c626 100644 --- a/examples/draft-preview/package.json +++ b/examples/draft-preview/package.json @@ -24,7 +24,7 @@ "dotenv": "^8.2.0", "escape-html": "^1.0.3", "graphql": "^16.9.0", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "latest", "react": "19.2.1", "react-dom": "19.2.1" diff --git a/examples/draft-preview/pnpm-lock.yaml b/examples/draft-preview/pnpm-lock.yaml index 0d568e2b3df..511883cc723 100644 --- a/examples/draft-preview/pnpm-lock.yaml +++ b/examples/draft-preview/pnpm-lock.yaml @@ -10,19 +10,19 @@ importers: dependencies: '@payloadcms/admin-bar': specifier: latest - version: 3.27.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 3.27.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@payloadcms/db-mongodb': specifier: latest version: 3.25.0(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2)) '@payloadcms/next': specifier: latest - version: 3.25.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.25.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) '@payloadcms/richtext-slate': specifier: latest - version: 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) '@payloadcms/ui': specifier: latest - version: 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) dotenv: specifier: ^8.2.0 version: 8.6.0 @@ -33,17 +33,17 @@ importers: specifier: ^16.9.0 version: 16.10.0 next: - specifier: ^15.0.0 - version: 15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + specifier: ^15.4.9 + version: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: latest version: 3.25.0(graphql@16.10.0)(typescript@5.5.2) react: - specifier: 19.0.0 - version: 19.0.0 + specifier: 19.2.1 + version: 19.2.1 react-dom: - specifier: 19.0.0 - version: 19.0.0(react@19.0.0) + specifier: 19.2.1 + version: 19.2.1(react@19.2.1) devDependencies: '@payloadcms/graphql': specifier: latest @@ -55,11 +55,11 @@ importers: specifier: ^1.0.2 version: 1.0.4 '@types/react': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1 '@types/react-dom': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -148,8 +148,8 @@ packages: peerDependencies: react: '>=16.8.0' - '@emnapi/runtime@1.3.1': - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -559,107 +559,139 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -704,53 +736,56 @@ packages: '@next/env@15.2.0': resolution: {integrity: sha512-eMgJu1RBXxxqqnuRJQh5RozhskoNUDHBFybvi+Z+yK9qzKeG7dadhv/Vp1YooSZmCnegf7JxWuapV77necLZNA==} + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + '@next/eslint-plugin-next@15.2.0': resolution: {integrity: sha512-jHFUG2OwmAuOASqq253RAEG/5BYcPHn27p1NoWZDCf4OdvdK0yRYWX92YKkL+Mk2s+GyJrmd/GATlL5b2IySpw==} - '@next/swc-darwin-arm64@15.2.0': - resolution: {integrity: sha512-rlp22GZwNJjFCyL7h5wz9vtpBVuCt3ZYjFWpEPBGzG712/uL1bbSkS675rVAUCRZ4hjoTJ26Q7IKhr5DfJrHDA==} + '@next/swc-darwin-arm64@15.5.7': + resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.2.0': - resolution: {integrity: sha512-DiU85EqSHogCz80+sgsx90/ecygfCSGl5P3b4XDRVZpgujBm5lp4ts7YaHru7eVTyZMjHInzKr+w0/7+qDrvMA==} + '@next/swc-darwin-x64@15.5.7': + resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.2.0': - resolution: {integrity: sha512-VnpoMaGukiNWVxeqKHwi8MN47yKGyki5q+7ql/7p/3ifuU2341i/gDwGK1rivk0pVYbdv5D8z63uu9yMw0QhpQ==} + '@next/swc-linux-arm64-gnu@15.5.7': + resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.2.0': - resolution: {integrity: sha512-ka97/ssYE5nPH4Qs+8bd8RlYeNeUVBhcnsNUmFM6VWEob4jfN9FTr0NBhXVi1XEJpj3cMfgSRW+LdE3SUZbPrw==} + '@next/swc-linux-arm64-musl@15.5.7': + resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.2.0': - resolution: {integrity: sha512-zY1JduE4B3q0k2ZCE+DAF/1efjTXUsKP+VXRtrt/rJCTgDlUyyryx7aOgYXNc1d8gobys/Lof9P9ze8IyRDn7Q==} + '@next/swc-linux-x64-gnu@15.5.7': + resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.2.0': - resolution: {integrity: sha512-QqvLZpurBD46RhaVaVBepkVQzh8xtlUN00RlG4Iq1sBheNugamUNPuZEH1r9X1YGQo1KqAe1iiShF0acva3jHQ==} + '@next/swc-linux-x64-musl@15.5.7': + resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.2.0': - resolution: {integrity: sha512-ODZ0r9WMyylTHAN6pLtvUtQlGXBL9voljv6ujSlcsjOxhtXPI1Ag6AhZK0SE8hEpR1374WZZ5w33ChpJd5fsjw==} + '@next/swc-win32-arm64-msvc@15.5.7': + resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.2.0': - resolution: {integrity: sha512-8+4Z3Z7xa13NdUuUAcpVNA6o76lNPniBd9Xbo02bwXQXnZgFvEopwY2at5+z7yHl47X9qbZpvwatZ2BRo3EdZw==} + '@next/swc-win32-x64-msvc@15.5.7': + resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -927,16 +962,18 @@ packages: '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/react-dom@19.0.1': - resolution: {integrity: sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 '@types/react-transition-group@4.4.12': resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} peerDependencies: '@types/react': '*' - '@types/react@19.0.1': - resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} '@types/webidl-conversions@7.0.3': resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} @@ -1170,13 +1207,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -1279,8 +1309,8 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} diff@5.2.0: @@ -1728,9 +1758,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -2038,13 +2065,13 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.2.0: - resolution: {integrity: sha512-VaiM7sZYX8KIAHBrRGSFytKknkrexNfGb8GlG6e93JqueCspuGte8i4ybn8z4ww1x3f2uzY4YpTaBEW4/hvsoQ==} + next@15.5.8: + resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 + '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 @@ -2251,10 +2278,10 @@ packages: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom@19.0.0: - resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + react-dom@19.2.1: + resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==} peerDependencies: - react: ^19.0.0 + react: ^19.2.1 react-image-crop@10.1.8: resolution: {integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==} @@ -2276,8 +2303,8 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' - react@19.0.0: - resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} + react@19.2.1: + resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==} engines: {node: '>=0.10.0'} readdirp@3.6.0: @@ -2358,6 +2385,9 @@ packages: scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + scmp@2.1.0: resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} @@ -2376,6 +2406,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2388,8 +2423,8 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -2419,9 +2454,6 @@ packages: sift@17.1.3: resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - simple-wcswidth@1.0.1: resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==} @@ -2808,32 +2840,32 @@ snapshots: '@date-fns/tz@1.2.0': {} - '@dnd-kit/accessibility@3.1.1(react@19.0.0)': + '@dnd-kit/accessibility@3.1.1(react@19.2.1)': dependencies: - react: 19.0.0 + react: 19.2.1 tslib: 2.8.1 - '@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@dnd-kit/accessibility': 3.1.1(react@19.2.1) + '@dnd-kit/utilities': 3.2.2(react@19.2.1) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) tslib: 2.8.1 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/utilities': 3.2.2(react@19.2.1) + react: 19.2.1 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.0.0)': + '@dnd-kit/utilities@3.2.2(react@19.2.1)': dependencies: - react: 19.0.0 + react: 19.2.1 tslib: 2.8.1 - '@emnapi/runtime@1.3.1': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -2876,19 +2908,19 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.0.1)(react@19.0.0)': + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.1)': dependencies: '@babel/runtime': 7.26.9 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.0.0) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.1) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.0.0 + react: 19.2.1 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 transitivePeerDependencies: - supports-color @@ -2904,9 +2936,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.0.0)': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.1)': dependencies: - react: 19.0.0 + react: 19.2.1 '@emotion/utils@1.4.2': {} @@ -3082,23 +3114,23 @@ snapshots: '@eslint/js@8.57.1': {} - '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: body-scroll-lock: 4.0.0-beta.0 focus-trap: 7.5.4 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/scroll-info@2.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - '@faceless-ui/window-info@3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/window-info@3.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) '@floating-ui/core@1.6.9': dependencies: @@ -3109,18 +3141,18 @@ snapshots: '@floating-ui/core': 1.6.9 '@floating-ui/utils': 0.2.9 - '@floating-ui/react-dom@2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react-dom@2.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: '@floating-ui/dom': 1.6.13 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - '@floating-ui/react@0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react@0.27.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react-dom': 2.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@floating-ui/utils': 0.2.9 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) tabbable: 6.2.0 '@floating-ui/utils@0.2.9': {} @@ -3137,79 +3169,101 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@img/sharp-darwin-arm64@0.33.5': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.0.4': + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.0.4': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.0.4': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.0.5': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.0.4': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-linux-arm64@0.33.5': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-arm@0.33.5': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linuxmusl-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true - '@img/sharp-wasm32@0.33.5': + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.3.1 + '@emnapi/runtime': 1.7.1 optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': optional: true '@jridgewell/gen-mapping@0.3.8': @@ -3237,12 +3291,12 @@ snapshots: dependencies: state-local: 1.0.7 - '@monaco-editor/react@4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@monaco-editor/react@4.7.0(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: '@monaco-editor/loader': 1.5.0 monaco-editor: 0.52.2 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) '@mongodb-js/saslprep@1.2.0': dependencies: @@ -3250,32 +3304,34 @@ snapshots: '@next/env@15.2.0': {} + '@next/env@15.5.8': {} + '@next/eslint-plugin-next@15.2.0': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.2.0': + '@next/swc-darwin-arm64@15.5.7': optional: true - '@next/swc-darwin-x64@15.2.0': + '@next/swc-darwin-x64@15.5.7': optional: true - '@next/swc-linux-arm64-gnu@15.2.0': + '@next/swc-linux-arm64-gnu@15.5.7': optional: true - '@next/swc-linux-arm64-musl@15.2.0': + '@next/swc-linux-arm64-musl@15.5.7': optional: true - '@next/swc-linux-x64-gnu@15.2.0': + '@next/swc-linux-x64-gnu@15.5.7': optional: true - '@next/swc-linux-x64-musl@15.2.0': + '@next/swc-linux-x64-musl@15.5.7': optional: true - '@next/swc-win32-arm64-msvc@15.2.0': + '@next/swc-win32-arm64-msvc@15.5.7': optional: true - '@next/swc-win32-x64-msvc@15.2.0': + '@next/swc-win32-x64-msvc@15.5.7': optional: true '@nodelib/fs.scandir@2.1.5': @@ -3292,10 +3348,10 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@payloadcms/admin-bar@3.27.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@payloadcms/admin-bar@3.27.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) '@payloadcms/db-mongodb@3.25.0(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))': dependencies: @@ -3326,12 +3382,12 @@ snapshots: transitivePeerDependencies: - typescript - '@payloadcms/next@3.25.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/next@3.25.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@payloadcms/graphql': 3.25.0(graphql@16.10.0)(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(typescript@5.5.2) '@payloadcms/translations': 3.25.0 - '@payloadcms/ui': 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/ui': 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) busboy: 1.6.0 dequal: 2.0.3 file-type: 19.3.0 @@ -3339,11 +3395,11 @@ snapshots: graphql-http: 1.22.4(graphql@16.10.0) graphql-playground-html: 1.6.30 http-status: 2.1.0 - next: 15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) path-to-regexp: 6.3.0 payload: 3.25.0(graphql@16.10.0)(typescript@5.5.2) qs-esm: 7.0.2 - react-diff-viewer-continued: 4.0.4(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-diff-viewer-continued: 4.0.4(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) sass: 1.77.4 uuid: 10.0.0 transitivePeerDependencies: @@ -3354,17 +3410,17 @@ snapshots: - supports-color - typescript - '@payloadcms/richtext-slate@3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/richtext-slate@3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)': dependencies: '@payloadcms/translations': 3.25.0 - '@payloadcms/ui': 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/ui': 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) is-hotkey: 0.2.0 payload: 3.25.0(graphql@16.10.0)(typescript@5.5.2) - react: 19.0.0 + react: 19.2.1 slate: 0.91.4 slate-history: 0.86.0(slate@0.91.4) slate-hyperscript: 0.81.3(slate@0.91.4) - slate-react: 0.92.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(slate@0.91.4) + slate-react: 0.92.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(slate@0.91.4) transitivePeerDependencies: - '@types/react' - monaco-editor @@ -3377,33 +3433,33 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/ui@3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)': dependencies: '@date-fns/tz': 1.2.0 - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/scroll-info': 2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/window-info': 3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@monaco-editor/react': 4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@faceless-ui/window-info': 3.0.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@monaco-editor/react': 4.7.0(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@payloadcms/translations': 3.25.0 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) object-to-formdata: 4.5.1 payload: 3.25.0(graphql@16.10.0)(typescript@5.5.2) qs-esm: 7.0.2 - react: 19.0.0 - react-datepicker: 7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-dom: 19.0.0(react@19.0.0) - react-image-crop: 10.1.8(react@19.0.0) - react-select: 5.9.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.1 + react-datepicker: 7.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react-dom: 19.2.1(react@19.2.1) + react-image-crop: 10.1.8(react@19.2.1) + react-select: 5.9.0(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) scheduler: 0.25.0 - sonner: 1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + sonner: 1.7.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1) ts-essentials: 10.0.3(typescript@5.5.2) - use-context-selector: 2.0.0(react@19.0.0)(scheduler@0.25.0) + use-context-selector: 2.0.0(react@19.2.1)(scheduler@0.25.0) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -3494,15 +3550,15 @@ snapshots: '@types/parse-json@4.0.2': {} - '@types/react-dom@19.0.1': + '@types/react-dom@19.2.1(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@types/react-transition-group@4.4.12(@types/react@19.0.1)': + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@types/react@19.0.1': + '@types/react@19.2.1': dependencies: csstype: 3.1.3 @@ -3791,18 +3847,6 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - colorette@2.0.20: {} commander@2.20.3: {} @@ -3893,7 +3937,7 @@ snapshots: dequal@2.0.3: {} - detect-libc@2.0.3: + detect-libc@2.1.2: optional: true diff@5.2.0: {} @@ -4101,8 +4145,8 @@ snapshots: '@typescript-eslint/parser': 8.25.0(eslint@8.57.1)(typescript@5.5.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) @@ -4121,7 +4165,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0)(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 @@ -4132,22 +4176,22 @@ snapshots: stable-hash: 0.0.4 tinyglobby: 0.2.12 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.25.0(eslint@8.57.1)(typescript@5.5.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1) + eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0)(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -4158,7 +4202,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.25.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -4535,9 +4579,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.2: - optional: true - is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -4825,28 +4866,26 @@ snapshots: natural-compare@1.4.0: {} - next@15.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): + next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.2.0 - '@swc/counter': 0.1.3 + '@next/env': 15.5.8 '@swc/helpers': 0.5.15 - busboy: 1.6.0 caniuse-lite: 1.0.30001701 postcss: 8.4.31 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + styled-jsx: 5.1.6(react@19.2.1) optionalDependencies: - '@next/swc-darwin-arm64': 15.2.0 - '@next/swc-darwin-x64': 15.2.0 - '@next/swc-linux-arm64-gnu': 15.2.0 - '@next/swc-linux-arm64-musl': 15.2.0 - '@next/swc-linux-x64-gnu': 15.2.0 - '@next/swc-linux-x64-musl': 15.2.0 - '@next/swc-win32-arm64-msvc': 15.2.0 - '@next/swc-win32-x64-msvc': 15.2.0 + '@next/swc-darwin-arm64': 15.5.7 + '@next/swc-darwin-x64': 15.5.7 + '@next/swc-linux-arm64-gnu': 15.5.7 + '@next/swc-linux-arm64-musl': 15.5.7 + '@next/swc-linux-x64-gnu': 15.5.7 + '@next/swc-linux-x64-musl': 15.5.7 + '@next/swc-win32-arm64-msvc': 15.5.7 + '@next/swc-win32-x64-msvc': 15.5.7 sass: 1.77.4 - sharp: 0.33.5 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -5073,65 +5112,65 @@ snapshots: quick-format-unescaped@4.0.4: {} - react-datepicker@7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-datepicker@7.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - '@floating-ui/react': 0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react': 0.27.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) clsx: 2.1.1 date-fns: 3.6.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - react-diff-viewer-continued@4.0.4(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-diff-viewer-continued@4.0.4(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: '@emotion/css': 11.13.5 - '@emotion/react': 11.14.0(@types/react@19.0.1)(react@19.0.0) + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.1) classnames: 2.5.1 diff: 5.2.0 memoize-one: 6.0.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) transitivePeerDependencies: - '@types/react' - supports-color - react-dom@19.0.0(react@19.0.0): + react-dom@19.2.1(react@19.2.1): dependencies: - react: 19.0.0 - scheduler: 0.25.0 + react: 19.2.1 + scheduler: 0.27.0 - react-image-crop@10.1.8(react@19.0.0): + react-image-crop@10.1.8(react@19.2.1): dependencies: - react: 19.0.0 + react: 19.2.1 react-is@16.13.1: {} - react-select@5.9.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-select@5.9.0(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: '@babel/runtime': 7.26.9 '@emotion/cache': 11.14.0 - '@emotion/react': 11.14.0(@types/react@19.0.1)(react@19.0.0) + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.1) '@floating-ui/dom': 1.6.13 - '@types/react-transition-group': 4.4.12(@types/react@19.0.1) + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - use-isomorphic-layout-effect: 1.2.0(@types/react@19.0.1)(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + use-isomorphic-layout-effect: 1.2.0(@types/react@19.2.1)(react@19.2.1) transitivePeerDependencies: - '@types/react' - supports-color - react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-transition-group@4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: '@babel/runtime': 7.26.9 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - react@19.0.0: {} + react@19.2.1: {} readdirp@3.6.0: dependencies: @@ -5222,6 +5261,8 @@ snapshots: scheduler@0.25.0: {} + scheduler@0.27.0: {} + scmp@2.1.0: {} scroll-into-view-if-needed@2.2.31: @@ -5234,6 +5275,9 @@ snapshots: semver@7.7.1: {} + semver@7.7.3: + optional: true + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5256,31 +5300,36 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 - sharp@0.33.5: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.3 - semver: 7.7.1 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -5319,11 +5368,6 @@ snapshots: sift@17.1.3: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - simple-wcswidth@1.0.1: {} sisteransi@1.0.5: {} @@ -5338,7 +5382,7 @@ snapshots: is-plain-object: 5.0.0 slate: 0.91.4 - slate-react@0.92.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(slate@0.91.4): + slate-react@0.92.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(slate@0.91.4): dependencies: '@juggle/resize-observer': 3.4.0 '@types/is-hotkey': 0.1.10 @@ -5347,8 +5391,8 @@ snapshots: is-hotkey: 0.1.8 is-plain-object: 5.0.0 lodash: 4.17.21 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) scroll-into-view-if-needed: 2.2.31 slate: 0.91.4 tiny-invariant: 1.0.6 @@ -5369,10 +5413,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + sonner@1.7.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) source-map-js@1.2.1: {} @@ -5453,10 +5497,10 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.4.2 - styled-jsx@5.1.6(react@19.0.0): + styled-jsx@5.1.6(react@19.2.1): dependencies: client-only: 0.0.1 - react: 19.0.0 + react: 19.2.1 stylis@4.2.0: {} @@ -5589,16 +5633,16 @@ snapshots: dependencies: punycode: 2.3.1 - use-context-selector@2.0.0(react@19.0.0)(scheduler@0.25.0): + use-context-selector@2.0.0(react@19.2.1)(scheduler@0.25.0): dependencies: - react: 19.0.0 + react: 19.2.1 scheduler: 0.25.0 - use-isomorphic-layout-effect@1.2.0(@types/react@19.0.1)(react@19.0.0): + use-isomorphic-layout-effect@1.2.0(@types/react@19.2.1)(react@19.2.1): dependencies: - react: 19.0.0 + react: 19.2.1 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 utf8-byte-length@1.0.5: {} diff --git a/examples/email/package.json b/examples/email/package.json index 277875266ab..ded982f1cb0 100644 --- a/examples/email/package.json +++ b/examples/email/package.json @@ -25,7 +25,7 @@ "ejs": "3.1.10", "graphql": "^16.9.0", "juice": "11.0.0", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1" diff --git a/examples/email/pnpm-lock.yaml b/examples/email/pnpm-lock.yaml index 8cb3c858453..674b157325a 100644 --- a/examples/email/pnpm-lock.yaml +++ b/examples/email/pnpm-lock.yaml @@ -4,29 +4,25 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -overrides: - '@types/react': npm:types-react@19.0.0-rc.1 - '@types/react-dom': npm:types-react-dom@19.0.0-rc.1 - importers: .: dependencies: '@payloadcms/db-mongodb': specifier: latest - version: 3.0.2(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2)) + version: 3.0.2(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)) '@payloadcms/email-nodemailer': specifier: latest - version: 3.0.2(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2)) + version: 3.0.2(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)) '@payloadcms/next': specifier: latest - version: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + version: 3.0.2(@types/react@19.2.1)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@payloadcms/richtext-lexical': specifier: latest - version: 3.0.2(zatxq7p6nyuk4dq5j2z7zpivdq) + version: 3.0.2(f1b6c08870f637092ed827a5beba5850) '@payloadcms/ui': specifier: latest - version: 3.0.2(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + version: 3.0.2(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -43,33 +39,33 @@ importers: specifier: 11.0.0 version: 11.0.0 next: - specifier: ^15.0.0 - version: 15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4) + specifier: ^15.4.9 + version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest - version: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + version: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) react: - specifier: 19.0.0-rc-65a56d0e-20241020 - version: 19.0.0-rc-65a56d0e-20241020 + specifier: ^19.2.1 + version: 19.2.2 react-dom: - specifier: 19.0.0-rc-65a56d0e-20241020 - version: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + specifier: ^19.2.1 + version: 19.2.2(react@19.2.2) devDependencies: '@payloadcms/graphql': specifier: latest - version: 3.0.2(graphql@16.9.0)(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(typescript@5.5.2) + version: 3.0.2(graphql@16.9.0)(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(typescript@5.5.2) '@swc/core': specifier: ^1.6.13 - version: 1.9.2(@swc/helpers@0.5.13) + version: 1.9.2(@swc/helpers@0.5.15) '@types/ejs': specifier: ^3.1.5 version: 3.1.5 '@types/react': - specifier: npm:types-react@19.0.0-rc.1 - version: types-react@19.0.0-rc.1 + specifier: 19.2.1 + version: 19.2.1 '@types/react-dom': - specifier: npm:types-react-dom@19.0.0-rc.1 - version: types-react-dom@19.0.0-rc.1 + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -138,8 +134,8 @@ packages: '@dnd-kit/core@6.0.8': resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} peerDependencies: - react: ^18.2.0 - react-dom: ^18.2.0 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@dnd-kit/sortable@7.0.2': resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} @@ -152,8 +148,8 @@ packages: peerDependencies: react: '>=16.8.0' - '@emnapi/runtime@1.3.1': - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -413,107 +409,139 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -631,53 +659,56 @@ packages: '@next/env@15.0.3': resolution: {integrity: sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==} + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + '@next/eslint-plugin-next@15.0.3': resolution: {integrity: sha512-3Ln/nHq2V+v8uIaxCR6YfYo7ceRgZNXfTd3yW1ukTaFbO+/I8jNakrjYWODvG9BuR2v5kgVtH/C8r0i11quOgw==} - '@next/swc-darwin-arm64@15.0.3': - resolution: {integrity: sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==} + '@next/swc-darwin-arm64@15.5.7': + resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.0.3': - resolution: {integrity: sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==} + '@next/swc-darwin-x64@15.5.7': + resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.0.3': - resolution: {integrity: sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==} + '@next/swc-linux-arm64-gnu@15.5.7': + resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.0.3': - resolution: {integrity: sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==} + '@next/swc-linux-arm64-musl@15.5.7': + resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.0.3': - resolution: {integrity: sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==} + '@next/swc-linux-x64-gnu@15.5.7': + resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.0.3': - resolution: {integrity: sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==} + '@next/swc-linux-x64-musl@15.5.7': + resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.0.3': - resolution: {integrity: sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==} + '@next/swc-win32-arm64-msvc@15.5.7': + resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.0.3': - resolution: {integrity: sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==} + '@next/swc-win32-x64-msvc@15.5.7': + resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -835,8 +866,8 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/helpers@0.5.13': - resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==} + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} '@swc/types@0.1.17': resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==} @@ -886,9 +917,17 @@ packages: '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 + '@types/react-transition-group@4.4.11': resolution: {integrity: sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1170,13 +1209,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -1295,8 +1327,8 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} devlop@1.1.0: @@ -1791,9 +1823,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-async-function@2.0.0: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} @@ -2217,16 +2246,16 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.0.3: - resolution: {integrity: sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==} + next@15.5.8: + resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 + '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-66855b96-20241106 - react-dom: ^18.2.0 || 19.0.0-rc-66855b96-20241106 + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': @@ -2456,10 +2485,10 @@ packages: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom@19.0.0-rc-65a56d0e-20241020: - resolution: {integrity: sha512-OrsgAX3LQ6JtdBJayK4nG1Hj5JebzWyhKSsrP/bmkeFxulb0nG2LaPloJ6kBkAxtgjiwRyGUciJ4+Qu64gy/KA==} + react-dom@19.2.2: + resolution: {integrity: sha512-fhyD2BLrew6qYf4NNtHff1rLXvzR25rq49p+FeqByOazc6TcSi2n8EYulo5C1PbH+1uBW++5S1SG7FcUU6mlDg==} peerDependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: ^19.2.2 react-error-boundary@3.1.4: resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} @@ -2498,8 +2527,8 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' - react@19.0.0-rc-65a56d0e-20241020: - resolution: {integrity: sha512-rZqpfd9PP/A97j9L1MR6fvWSMgs3khgIyLd0E+gYoCcLrxXndj+ySPRVlDPDC3+f7rm8efHNL4B6HeapqU6gzw==} + react@19.2.2: + resolution: {integrity: sha512-BdOGOY8OKRBcgoDkwqA8Q5XvOIhoNx/Sh6BnGJlet2Abt0X5BK0BDrqGyQgLhAVjD2nAg5f6o01u/OPUhG022Q==} engines: {node: '>=0.10.0'} readdirp@3.6.0: @@ -2578,8 +2607,8 @@ packages: scheduler@0.0.0-experimental-3edc000d-20240926: resolution: {integrity: sha512-360BMNajOhMyrirau0pzWVgeakvrfjbfdqHnX2K+tSGTmn6tBN+6K5NhhaebqeXXWyCU3rl5FApjgF2GN0W5JA==} - scheduler@0.25.0-rc-65a56d0e-20241020: - resolution: {integrity: sha512-HxWcXSy0sNnf+TKRkMwyVD1z19AAVQ4gUub8m7VxJUUfSu3J4lr1T+AagohKEypiW5dbQhJuCtAumPY6z9RQ1g==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} scmp@2.1.0: resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} @@ -2596,6 +2625,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2604,8 +2638,8 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -2623,9 +2657,6 @@ packages: sift@17.1.3: resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - simple-wcswidth@1.0.1: resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==} @@ -2812,12 +2843,6 @@ packages: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} - types-react-dom@19.0.0-rc.1: - resolution: {integrity: sha512-VSLZJl8VXCD0fAWp7DUTFUDCcZ8DVXOQmjhJMD03odgeFmu14ZQJHCXeETm3BEAhJqfgJaFkLnGkQv88sRx0fQ==} - - types-react@19.0.0-rc.1: - resolution: {integrity: sha512-RshndUfqTW6K3STLPis8BtAYCGOkMbtvYsi90gmVNDZBXUyUc5juf2PE9LfS/JmOlUIRO8cWTS/1MTnmhjDqyQ==} - typescript@5.5.2: resolution: {integrity: sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==} engines: {node: '>=14.17'} @@ -3027,32 +3052,32 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@dnd-kit/accessibility@3.1.0(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/accessibility@3.1.0(react@19.2.2)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/core@6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/accessibility': 3.1.0(react@19.0.0-rc-65a56d0e-20241020) - '@dnd-kit/utilities': 3.2.2(react@19.0.0-rc-65a56d0e-20241020) - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + '@dnd-kit/accessibility': 3.1.0(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tslib: 2.8.1 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@dnd-kit/utilities': 3.2.2(react@19.0.0-rc-65a56d0e-20241020) - react: 19.0.0-rc-65a56d0e-20241020 + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/utilities@3.2.2(react@19.2.2)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 tslib: 2.8.1 - '@emnapi/runtime@1.3.1': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -3095,19 +3120,19 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.13.5(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)': + '@emotion/react@11.13.5(@types/react@19.2.1)(react@19.2.2)': dependencies: '@babel/runtime': 7.26.0 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.13.5 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@19.0.0-rc-65a56d0e-20241020) + '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@19.2.2) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 optionalDependencies: - '@types/react': types-react@19.0.0-rc.1 + '@types/react': 19.2.1 transitivePeerDependencies: - supports-color @@ -3123,9 +3148,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@19.0.0-rc-65a56d0e-20241020)': + '@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@19.2.2)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 '@emotion/utils@1.4.2': {} @@ -3226,23 +3251,23 @@ snapshots: '@eslint/js@8.57.1': {} - '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: body-scroll-lock: 4.0.0-beta.0 focus-trap: 7.5.4 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-transition-group: 4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) - '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@floating-ui/core@1.6.8': dependencies: @@ -3253,18 +3278,18 @@ snapshots: '@floating-ui/core': 1.6.8 '@floating-ui/utils': 0.2.8 - '@floating-ui/react-dom@2.1.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@floating-ui/react-dom@2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@floating-ui/dom': 1.6.12 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@floating-ui/react@0.26.28(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@floating-ui/react@0.26.28(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@floating-ui/react-dom': 2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@floating-ui/utils': 0.2.8 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tabbable: 6.2.0 '@floating-ui/utils@0.2.8': {} @@ -3281,79 +3306,101 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@img/sharp-darwin-arm64@0.33.5': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-arm64@1.0.4': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.0.4': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.0.4': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.0.5': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.0.4': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - '@img/sharp-linux-arm64@0.33.5': + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-arm@0.33.5': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-wasm32@0.33.5': + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.3.1 + '@emnapi/runtime': 1.7.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-ia32@0.34.5': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-x64@0.34.5': optional: true '@jridgewell/gen-mapping@0.3.5': @@ -3389,7 +3436,7 @@ snapshots: lexical: 0.20.0 prismjs: 1.29.0 - '@lexical/devtools-core@0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@lexical/devtools-core@0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@lexical/html': 0.20.0 '@lexical/link': 0.20.0 @@ -3397,8 +3444,8 @@ snapshots: '@lexical/table': 0.20.0 '@lexical/utils': 0.20.0 lexical: 0.20.0 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@lexical/dragon@0.20.0': dependencies: @@ -3464,11 +3511,11 @@ snapshots: '@lexical/utils': 0.20.0 lexical: 0.20.0 - '@lexical/react@0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(yjs@13.6.20)': + '@lexical/react@0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.20)': dependencies: '@lexical/clipboard': 0.20.0 '@lexical/code': 0.20.0 - '@lexical/devtools-core': 0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@lexical/devtools-core': 0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@lexical/dragon': 0.20.0 '@lexical/hashtag': 0.20.0 '@lexical/history': 0.20.0 @@ -3485,9 +3532,9 @@ snapshots: '@lexical/utils': 0.20.0 '@lexical/yjs': 0.20.0(yjs@13.6.20) lexical: 0.20.0 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-error-boundary: 3.1.4(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 3.1.4(react@19.2.2) transitivePeerDependencies: - yjs @@ -3531,12 +3578,12 @@ snapshots: monaco-editor: 0.52.0 state-local: 1.0.7 - '@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@monaco-editor/loader': 1.4.0(monaco-editor@0.52.0) monaco-editor: 0.52.0 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@mongodb-js/saslprep@1.1.9': dependencies: @@ -3544,32 +3591,34 @@ snapshots: '@next/env@15.0.3': {} + '@next/env@15.5.8': {} + '@next/eslint-plugin-next@15.0.3': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.0.3': + '@next/swc-darwin-arm64@15.5.7': optional: true - '@next/swc-darwin-x64@15.0.3': + '@next/swc-darwin-x64@15.5.7': optional: true - '@next/swc-linux-arm64-gnu@15.0.3': + '@next/swc-linux-arm64-gnu@15.5.7': optional: true - '@next/swc-linux-arm64-musl@15.0.3': + '@next/swc-linux-arm64-musl@15.5.7': optional: true - '@next/swc-linux-x64-gnu@15.0.3': + '@next/swc-linux-x64-gnu@15.5.7': optional: true - '@next/swc-linux-x64-musl@15.0.3': + '@next/swc-linux-x64-musl@15.5.7': optional: true - '@next/swc-win32-arm64-msvc@15.0.3': + '@next/swc-win32-arm64-msvc@15.5.7': optional: true - '@next/swc-win32-x64-msvc@15.0.3': + '@next/swc-win32-x64-msvc@15.5.7': optional: true '@nodelib/fs.scandir@2.1.5': @@ -3586,13 +3635,13 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@payloadcms/db-mongodb@3.0.2(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))': + '@payloadcms/db-mongodb@3.0.2(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))': dependencies: http-status: 1.6.2 mongoose: 8.8.1 mongoose-aggregate-paginate-v2: 1.1.2 mongoose-paginate-v2: 1.8.5 - payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) prompts: 2.4.2 uuid: 10.0.0 transitivePeerDependencies: @@ -3605,41 +3654,41 @@ snapshots: - socks - supports-color - '@payloadcms/email-nodemailer@3.0.2(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))': + '@payloadcms/email-nodemailer@3.0.2(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))': dependencies: nodemailer: 6.9.10 - payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) - '@payloadcms/graphql@3.0.2(graphql@16.9.0)(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(typescript@5.5.2)': + '@payloadcms/graphql@3.0.2(graphql@16.9.0)(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(typescript@5.5.2)': dependencies: graphql: 16.9.0 graphql-scalars: 1.22.2(graphql@16.9.0) - payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) pluralize: 8.0.0 ts-essentials: 10.0.3(typescript@5.5.2) tsx: 4.19.2 transitivePeerDependencies: - typescript - '@payloadcms/next@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2)': + '@payloadcms/next@3.0.2(@types/react@19.2.1)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@payloadcms/graphql': 3.0.2(graphql@16.9.0)(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(typescript@5.5.2) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@payloadcms/graphql': 3.0.2(graphql@16.9.0)(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(typescript@5.5.2) '@payloadcms/translations': 3.0.2 - '@payloadcms/ui': 3.0.2(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + '@payloadcms/ui': 3.0.2(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) busboy: 1.6.0 file-type: 19.3.0 graphql: 16.9.0 graphql-http: 1.22.3(graphql@16.9.0) graphql-playground-html: 1.6.30 http-status: 1.6.2 - next: 15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) path-to-regexp: 6.3.0 - payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) qs-esm: 7.0.2 - react-diff-viewer-continued: 3.2.6(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + react-diff-viewer-continued: 3.2.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2) sass: 1.77.4 - sonner: 1.7.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + sonner: 1.7.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -3649,22 +3698,22 @@ snapshots: - supports-color - typescript - '@payloadcms/richtext-lexical@3.0.2(zatxq7p6nyuk4dq5j2z7zpivdq)': + '@payloadcms/richtext-lexical@3.0.2(f1b6c08870f637092ed827a5beba5850)': dependencies: - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@lexical/headless': 0.20.0 '@lexical/link': 0.20.0 '@lexical/list': 0.20.0 '@lexical/mark': 0.20.0 - '@lexical/react': 0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(yjs@13.6.20) + '@lexical/react': 0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.20) '@lexical/rich-text': 0.20.0 '@lexical/selection': 0.20.0 '@lexical/table': 0.20.0 '@lexical/utils': 0.20.0 - '@payloadcms/next': 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + '@payloadcms/next': 3.0.2(@types/react@19.2.1)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@payloadcms/translations': 3.0.2 - '@payloadcms/ui': 3.0.2(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + '@payloadcms/ui': 3.0.2(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -3674,10 +3723,10 @@ snapshots: mdast-util-from-markdown: 2.0.2 mdast-util-mdx-jsx: 3.1.3 micromark-extension-mdx-jsx: 3.0.1 - payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-error-boundary: 4.0.13(react@19.0.0-rc-65a56d0e-20241020) + payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 4.0.13(react@19.2.2) ts-essentials: 10.0.3(typescript@5.5.2) uuid: 10.0.0 transitivePeerDependencies: @@ -3691,34 +3740,34 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.0.2(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2)': + '@payloadcms/ui@3.0.2(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/translations': 3.0.2 body-scroll-lock: 4.0.0-beta.0 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) object-to-formdata: 4.5.1 - payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) qs-esm: 7.0.2 - react: 19.0.0-rc-65a56d0e-20241020 - react-animate-height: 2.1.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - react-datepicker: 6.9.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-image-crop: 10.1.8(react@19.0.0-rc-65a56d0e-20241020) - react-select: 5.8.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + react: 19.2.2 + react-animate-height: 2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-datepicker: 6.9.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-dom: 19.2.2(react@19.2.2) + react-image-crop: 10.1.8(react@19.2.2) + react-select: 5.8.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) scheduler: 0.0.0-experimental-3edc000d-20240926 - sonner: 1.7.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + sonner: 1.7.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) ts-essentials: 10.0.3(typescript@5.5.2) - use-context-selector: 2.0.0(react@19.0.0-rc-65a56d0e-20241020)(scheduler@0.0.0-experimental-3edc000d-20240926) + use-context-selector: 2.0.0(react@19.2.2)(scheduler@0.0.0-experimental-3edc000d-20240926) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -3760,7 +3809,7 @@ snapshots: '@swc/core-win32-x64-msvc@1.9.2': optional: true - '@swc/core@1.9.2(@swc/helpers@0.5.13)': + '@swc/core@1.9.2(@swc/helpers@0.5.15)': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.17 @@ -3775,11 +3824,11 @@ snapshots: '@swc/core-win32-arm64-msvc': 1.9.2 '@swc/core-win32-ia32-msvc': 1.9.2 '@swc/core-win32-x64-msvc': 1.9.2 - '@swc/helpers': 0.5.13 + '@swc/helpers': 0.5.15 '@swc/counter@0.1.3': {} - '@swc/helpers@0.5.13': + '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 @@ -3831,9 +3880,17 @@ snapshots: '@types/parse-json@4.0.2': {} + '@types/react-dom@19.2.1(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 + '@types/react-transition-group@4.4.11': dependencies: - '@types/react': types-react@19.0.0-rc.1 + '@types/react': 19.2.1 + + '@types/react@19.2.1': + dependencies: + csstype: 3.1.3 '@types/unist@2.0.11': {} @@ -4162,18 +4219,6 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - colorette@2.0.20: {} commander@12.1.0: {} @@ -4282,7 +4327,7 @@ snapshots: dequal@2.0.3: {} - detect-libc@2.0.3: + detect-libc@2.1.2: optional: true devlop@1.1.0: @@ -4532,7 +4577,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -4545,7 +4590,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -4567,7 +4612,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -4961,9 +5006,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.2: - optional: true - is-async-function@2.0.0: dependencies: has-tostringtag: 1.0.2 @@ -5490,28 +5532,26 @@ snapshots: natural-compare@1.4.0: {} - next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4): + next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): dependencies: - '@next/env': 15.0.3 - '@swc/counter': 0.1.3 - '@swc/helpers': 0.5.13 - busboy: 1.6.0 + '@next/env': 15.5.8 + '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001683 postcss: 8.4.31 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - styled-jsx: 5.1.6(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + styled-jsx: 5.1.6(react@19.2.2) optionalDependencies: - '@next/swc-darwin-arm64': 15.0.3 - '@next/swc-darwin-x64': 15.0.3 - '@next/swc-linux-arm64-gnu': 15.0.3 - '@next/swc-linux-arm64-musl': 15.0.3 - '@next/swc-linux-x64-gnu': 15.0.3 - '@next/swc-linux-x64-musl': 15.0.3 - '@next/swc-win32-arm64-msvc': 15.0.3 - '@next/swc-win32-x64-msvc': 15.0.3 + '@next/swc-darwin-arm64': 15.5.7 + '@next/swc-darwin-x64': 15.5.7 + '@next/swc-linux-arm64-gnu': 15.5.7 + '@next/swc-linux-arm64-musl': 15.5.7 + '@next/swc-linux-x64-gnu': 15.5.7 + '@next/swc-linux-x64-musl': 15.5.7 + '@next/swc-win32-arm64-msvc': 15.5.7 + '@next/swc-win32-x64-msvc': 15.5.7 sass: 1.77.4 - sharp: 0.33.5 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -5634,9 +5674,9 @@ snapshots: path-type@4.0.0: {} - payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2): + payload@3.0.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2): dependencies: - '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@next/env': 15.0.3 '@payloadcms/translations': 3.0.2 '@types/busboy': 1.5.4 @@ -5762,88 +5802,88 @@ snapshots: quick-format-unescaped@4.0.4: {} - react-animate-height@2.1.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-animate-height@2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: classnames: 2.5.1 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react-datepicker@6.9.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-datepicker@6.9.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - '@floating-ui/react': 0.26.28(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@floating-ui/react': 0.26.28(react-dom@19.2.2(react@19.2.2))(react@19.2.2) clsx: 2.1.1 date-fns: 3.6.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-onclickoutside: 6.13.1(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-onclickoutside: 6.13.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2) - react-diff-viewer-continued@3.2.6(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-diff-viewer-continued@3.2.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@emotion/css': 11.13.5 classnames: 2.5.1 diff: 5.2.0 memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) transitivePeerDependencies: - supports-color - react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020): + react-dom@19.2.2(react@19.2.2): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - scheduler: 0.25.0-rc-65a56d0e-20241020 + react: 19.2.2 + scheduler: 0.27.0 - react-error-boundary@3.1.4(react@19.0.0-rc-65a56d0e-20241020): + react-error-boundary@3.1.4(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 - react-error-boundary@4.0.13(react@19.0.0-rc-65a56d0e-20241020): + react-error-boundary@4.0.13(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 - react-image-crop@10.1.8(react@19.0.0-rc-65a56d0e-20241020): + react-image-crop@10.1.8(react@19.2.2): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 react-is@16.13.1: {} - react-onclickoutside@6.13.1(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-onclickoutside@6.13.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react-select@5.8.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1): + react-select@5.8.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 '@emotion/cache': 11.13.5 - '@emotion/react': 11.13.5(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + '@emotion/react': 11.13.5(@types/react@19.2.1)(react@19.2.2) '@floating-ui/dom': 1.6.12 '@types/react-transition-group': 4.4.11 memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-transition-group: 4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - use-isomorphic-layout-effect: 1.1.2(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + use-isomorphic-layout-effect: 1.1.2(@types/react@19.2.1)(react@19.2.2) transitivePeerDependencies: - '@types/react' - supports-color - react-transition-group@4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-transition-group@4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react@19.0.0-rc-65a56d0e-20241020: {} + react@19.2.2: {} readdirp@3.6.0: dependencies: @@ -5927,7 +5967,7 @@ snapshots: scheduler@0.0.0-experimental-3edc000d-20240926: {} - scheduler@0.25.0-rc-65a56d0e-20241020: {} + scheduler@0.27.0: {} scmp@2.1.0: {} @@ -5937,6 +5977,9 @@ snapshots: semver@7.6.3: {} + semver@7.7.3: + optional: true + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5953,31 +5996,36 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 - sharp@0.33.5: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.3 - semver: 7.6.3 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -5995,11 +6043,6 @@ snapshots: sift@17.1.3: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - simple-wcswidth@1.0.1: {} sisteransi@1.0.5: {} @@ -6010,10 +6053,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@1.7.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + sonner@1.7.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) source-map-js@1.2.1: {} @@ -6092,10 +6135,10 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.3.1 - styled-jsx@5.1.6(react@19.0.0-rc-65a56d0e-20241020): + styled-jsx@5.1.6(react@19.2.2): dependencies: client-only: 0.0.1 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 stylis@4.2.0: {} @@ -6199,14 +6242,6 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - types-react-dom@19.0.0-rc.1: - dependencies: - '@types/react': types-react@19.0.0-rc.1 - - types-react@19.0.0-rc.1: - dependencies: - csstype: 3.1.3 - typescript@5.5.2: {} uint8array-extras@1.4.0: {} @@ -6249,16 +6284,16 @@ snapshots: dependencies: punycode: 2.3.1 - use-context-selector@2.0.0(react@19.0.0-rc-65a56d0e-20241020)(scheduler@0.0.0-experimental-3edc000d-20240926): + use-context-selector@2.0.0(react@19.2.2)(scheduler@0.0.0-experimental-3edc000d-20240926): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 scheduler: 0.0.0-experimental-3edc000d-20240926 - use-isomorphic-layout-effect@1.1.2(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1): + use-isomorphic-layout-effect@1.1.2(@types/react@19.2.1)(react@19.2.2): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 optionalDependencies: - '@types/react': types-react@19.0.0-rc.1 + '@types/react': 19.2.1 utf8-byte-length@1.0.5: {} diff --git a/examples/form-builder/package.json b/examples/form-builder/package.json index e12ccc0cad7..a48bb55198d 100644 --- a/examples/form-builder/package.json +++ b/examples/form-builder/package.json @@ -25,7 +25,7 @@ "@payloadcms/richtext-lexical": "latest", "cross-env": "^7.0.3", "graphql": "^16.9.0", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "latest", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/examples/form-builder/pnpm-lock.yaml b/examples/form-builder/pnpm-lock.yaml index bef2ca8a8aa..1907edd79b8 100644 --- a/examples/form-builder/pnpm-lock.yaml +++ b/examples/form-builder/pnpm-lock.yaml @@ -4,38 +4,34 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -overrides: - '@types/react': npm:types-react@19.0.0-rc.1 - '@types/react-dom': npm:types-react-dom@19.0.0-rc.1 - importers: .: dependencies: '@apollo/client': specifier: ^3.7.0 - version: 3.11.10(graphql@16.9.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + version: 3.11.10(@types/react@19.2.1)(graphql@16.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@faceless-ui/css-grid': specifier: ^1.2.0 - version: 1.2.1(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + version: 1.2.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@faceless-ui/modal': specifier: ^2.0.2 - version: 2.0.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + version: 2.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@payloadcms/db-mongodb': specifier: latest - version: 3.2.2(@aws-sdk/credential-providers@3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0)))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2)) + version: 3.2.2(@aws-sdk/credential-providers@3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0)))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)) '@payloadcms/next': specifier: latest - version: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + version: 3.2.2(@types/react@19.2.1)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) '@payloadcms/plugin-cloud': specifier: latest - version: 3.0.2(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2)) + version: 3.0.2(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)) '@payloadcms/plugin-form-builder': specifier: latest - version: 3.2.2(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + version: 3.2.2(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) '@payloadcms/richtext-lexical': specifier: latest - version: 3.2.2(lzfza3uy2uviaruymssnnecmse) + version: 3.2.2(66588668249d7fc5cb26e632554578c6) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -43,36 +39,36 @@ importers: specifier: ^16.9.0 version: 16.9.0 next: - specifier: ^15.0.0 - version: 15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4) + specifier: ^15.4.9 + version: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: latest - version: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + version: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) react: - specifier: 19.0.0-rc-65a56d0e-20241020 - version: 19.0.0-rc-65a56d0e-20241020 + specifier: 19.2.1 + version: 19.2.1 react-dom: - specifier: 19.0.0-rc-65a56d0e-20241020 - version: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + specifier: 19.2.1 + version: 19.2.1(react@19.2.1) react-hook-form: specifier: ^7.41.0 - version: 7.53.2(react@19.0.0-rc-65a56d0e-20241020) + version: 7.53.2(react@19.2.1) react-select: - specifier: ^5.8.0 - version: 5.8.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + specifier: ^5.9.0 + version: 5.10.2(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) devDependencies: '@payloadcms/graphql': specifier: latest - version: 3.2.2(graphql@16.9.0)(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(typescript@5.5.2) + version: 3.2.2(graphql@16.9.0)(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(typescript@5.5.2) '@types/node': specifier: ^20.11.25 version: 20.17.9 '@types/react': - specifier: npm:types-react@19.0.0-rc.1 - version: types-react@19.0.0-rc.1 + specifier: 19.2.1 + version: 19.2.1 '@types/react-dom': - specifier: npm:types-react-dom@19.0.0-rc.1 - version: types-react-dom@19.0.0-rc.1 + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) dotenv: specifier: ^16.4.5 version: 16.4.5 @@ -352,8 +348,8 @@ packages: '@dnd-kit/core@6.0.8': resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} peerDependencies: - react: ^18.2.0 - react-dom: ^18.2.0 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@dnd-kit/sortable@7.0.2': resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} @@ -366,8 +362,8 @@ packages: peerDependencies: react: '>=16.8.0' - '@emnapi/runtime@1.3.1': - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -644,107 +640,139 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -862,53 +890,56 @@ packages: '@next/env@15.0.3': resolution: {integrity: sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==} + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + '@next/eslint-plugin-next@15.0.3': resolution: {integrity: sha512-3Ln/nHq2V+v8uIaxCR6YfYo7ceRgZNXfTd3yW1ukTaFbO+/I8jNakrjYWODvG9BuR2v5kgVtH/C8r0i11quOgw==} - '@next/swc-darwin-arm64@15.0.3': - resolution: {integrity: sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==} + '@next/swc-darwin-arm64@15.5.7': + resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.0.3': - resolution: {integrity: sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==} + '@next/swc-darwin-x64@15.5.7': + resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.0.3': - resolution: {integrity: sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==} + '@next/swc-linux-arm64-gnu@15.5.7': + resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.0.3': - resolution: {integrity: sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==} + '@next/swc-linux-arm64-musl@15.5.7': + resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.0.3': - resolution: {integrity: sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==} + '@next/swc-linux-x64-gnu@15.5.7': + resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.0.3': - resolution: {integrity: sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==} + '@next/swc-linux-x64-musl@15.5.7': + resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.0.3': - resolution: {integrity: sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==} + '@next/swc-win32-arm64-msvc@15.5.7': + resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.0.3': - resolution: {integrity: sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==} + '@next/swc-win32-x64-msvc@15.5.7': + resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1203,11 +1234,8 @@ packages: resolution: {integrity: sha512-/aMXPANhMOlMPjfPtSrDfPeVP8l56SJlz93xeiLmhLe5xvlXA5T3abZ2ilEsDEPeY9T/wnN/vNGn9wa1SbufWA==} engines: {node: '>=16.0.0'} - '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - - '@swc/helpers@0.5.13': - resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==} + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} @@ -1251,9 +1279,17 @@ packages: '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 + '@types/react-transition-group@4.4.11': resolution: {integrity: sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1552,13 +1588,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -1666,8 +1695,8 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} devlop@1.1.0: @@ -2124,9 +2153,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-async-function@2.0.0: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} @@ -2539,16 +2565,16 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.0.3: - resolution: {integrity: sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==} + next@15.5.8: + resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 + '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-66855b96-20241106 - react-dom: ^18.2.0 || 19.0.0-rc-66855b96-20241106 + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': @@ -2775,10 +2801,10 @@ packages: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom@19.0.0-rc-65a56d0e-20241020: - resolution: {integrity: sha512-OrsgAX3LQ6JtdBJayK4nG1Hj5JebzWyhKSsrP/bmkeFxulb0nG2LaPloJ6kBkAxtgjiwRyGUciJ4+Qu64gy/KA==} + react-dom@19.2.1: + resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==} peerDependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: ^19.2.1 react-error-boundary@3.1.4: resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} @@ -2811,14 +2837,14 @@ packages: react: ^15.5.x || ^16.x || ^17.x || ^18.x react-dom: ^15.5.x || ^16.x || ^17.x || ^18.x - react-select@5.8.0: - resolution: {integrity: sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==} + react-select@5.10.2: + resolution: {integrity: sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-select@5.8.3: - resolution: {integrity: sha512-lVswnIq8/iTj1db7XCG74M/3fbGB6ZaluCzvwPGT5ZOjCdL/k0CLWhEK0vCBLuU5bHTEf6Gj8jtSvi+3v+tO1w==} + react-select@5.8.0: + resolution: {integrity: sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -2829,8 +2855,8 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' - react@19.0.0-rc-65a56d0e-20241020: - resolution: {integrity: sha512-rZqpfd9PP/A97j9L1MR6fvWSMgs3khgIyLd0E+gYoCcLrxXndj+ySPRVlDPDC3+f7rm8efHNL4B6HeapqU6gzw==} + react@19.2.1: + resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==} engines: {node: '>=0.10.0'} readable-stream@3.6.2: @@ -2859,7 +2885,7 @@ packages: rehackt@0.1.0: resolution: {integrity: sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==} peerDependencies: - '@types/react': npm:types-react@19.0.0-rc.1 + '@types/react': '*' react: '*' peerDependenciesMeta: '@types/react': @@ -2928,8 +2954,8 @@ packages: scheduler@0.0.0-experimental-3edc000d-20240926: resolution: {integrity: sha512-360BMNajOhMyrirau0pzWVgeakvrfjbfdqHnX2K+tSGTmn6tBN+6K5NhhaebqeXXWyCU3rl5FApjgF2GN0W5JA==} - scheduler@0.25.0-rc-65a56d0e-20241020: - resolution: {integrity: sha512-HxWcXSy0sNnf+TKRkMwyVD1z19AAVQ4gUub8m7VxJUUfSu3J4lr1T+AagohKEypiW5dbQhJuCtAumPY6z9RQ1g==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} scmp@2.1.0: resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} @@ -2946,6 +2972,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2954,8 +2985,8 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -2973,9 +3004,6 @@ packages: sift@17.1.3: resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - simple-wcswidth@1.0.1: resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==} @@ -3185,12 +3213,6 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - types-react-dom@19.0.0-rc.1: - resolution: {integrity: sha512-VSLZJl8VXCD0fAWp7DUTFUDCcZ8DVXOQmjhJMD03odgeFmu14ZQJHCXeETm3BEAhJqfgJaFkLnGkQv88sRx0fQ==} - - types-react@19.0.0-rc.1: - resolution: {integrity: sha512-RshndUfqTW6K3STLPis8BtAYCGOkMbtvYsi90gmVNDZBXUyUc5juf2PE9LfS/JmOlUIRO8cWTS/1MTnmhjDqyQ==} - typescript@5.5.2: resolution: {integrity: sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==} engines: {node: '>=14.17'} @@ -3242,6 +3264,15 @@ packages: '@types/react': optional: true + use-isomorphic-layout-effect@1.2.1: + resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + utf8-byte-length@1.0.5: resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} @@ -3347,7 +3378,7 @@ snapshots: '@types/json-schema': 7.0.15 js-yaml: 4.1.0 - '@apollo/client@3.11.10(graphql@16.9.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)': + '@apollo/client@3.11.10(@types/react@19.2.1)(graphql@16.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@16.9.0) '@wry/caches': 1.0.1 @@ -3358,15 +3389,15 @@ snapshots: hoist-non-react-statics: 3.3.2 optimism: 0.18.1 prop-types: 15.8.1 - rehackt: 0.1.0(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + rehackt: 0.1.0(@types/react@19.2.1)(react@19.2.1) response-iterator: 0.2.6 symbol-observable: 4.0.0 ts-invariant: 0.10.3 tslib: 2.8.1 zen-observable-ts: 1.2.5 optionalDependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) transitivePeerDependencies: - '@types/react' @@ -4039,32 +4070,32 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@dnd-kit/accessibility@3.1.1(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/accessibility@3.1.1(react@19.2.1)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 tslib: 2.8.1 - '@dnd-kit/core@6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.0.0-rc-65a56d0e-20241020) - '@dnd-kit/utilities': 3.2.2(react@19.0.0-rc-65a56d0e-20241020) - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + '@dnd-kit/accessibility': 3.1.1(react@19.2.1) + '@dnd-kit/utilities': 3.2.2(react@19.2.1) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) tslib: 2.8.1 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@dnd-kit/utilities': 3.2.2(react@19.0.0-rc-65a56d0e-20241020) - react: 19.0.0-rc-65a56d0e-20241020 + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/utilities': 3.2.2(react@19.2.1) + react: 19.2.1 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/utilities@3.2.2(react@19.2.1)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 tslib: 2.8.1 - '@emnapi/runtime@1.3.1': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -4107,19 +4138,19 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.13.5(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)': + '@emotion/react@11.13.5(@types/react@19.2.1)(react@19.2.1)': dependencies: '@babel/runtime': 7.26.0 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.13.5 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@19.0.0-rc-65a56d0e-20241020) + '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@19.2.1) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 optionalDependencies: - '@types/react': types-react@19.0.0-rc.1 + '@types/react': 19.2.1 transitivePeerDependencies: - supports-color @@ -4135,9 +4166,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@19.0.0-rc-65a56d0e-20241020)': + '@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@19.2.1)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 '@emotion/utils@1.4.2': {} @@ -4238,37 +4269,37 @@ snapshots: '@eslint/js@8.57.1': {} - '@faceless-ui/css-grid@1.2.1(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/css-grid@1.2.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - '@faceless-ui/modal@2.0.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/modal@2.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: body-scroll-lock: 3.1.5 focus-trap: 6.9.4 qs: 6.13.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-transition-group: 4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: body-scroll-lock: 4.0.0-beta.0 focus-trap: 7.5.4 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-transition-group: 4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) '@floating-ui/core@1.6.8': dependencies: @@ -4279,18 +4310,18 @@ snapshots: '@floating-ui/core': 1.6.8 '@floating-ui/utils': 0.2.8 - '@floating-ui/react-dom@2.1.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@floating-ui/react-dom@2.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: '@floating-ui/dom': 1.6.12 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - '@floating-ui/react@0.26.28(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@floating-ui/react@0.26.28(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@floating-ui/react-dom': 2.1.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@floating-ui/utils': 0.2.8 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) tabbable: 6.2.0 '@floating-ui/utils@0.2.8': {} @@ -4311,79 +4342,101 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@img/sharp-darwin-arm64@0.33.5': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.0.4': + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.0.4': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.0.4': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.0.5': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.0.4': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-linux-arm64@0.33.5': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-arm@0.33.5': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-wasm32@0.33.5': + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.3.1 + '@emnapi/runtime': 1.7.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-ia32@0.34.5': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-x64@0.34.5': optional: true '@jridgewell/gen-mapping@0.3.5': @@ -4419,7 +4472,7 @@ snapshots: lexical: 0.20.0 prismjs: 1.29.0 - '@lexical/devtools-core@0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@lexical/devtools-core@0.20.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: '@lexical/html': 0.20.0 '@lexical/link': 0.20.0 @@ -4427,8 +4480,8 @@ snapshots: '@lexical/table': 0.20.0 '@lexical/utils': 0.20.0 lexical: 0.20.0 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) '@lexical/dragon@0.20.0': dependencies: @@ -4494,11 +4547,11 @@ snapshots: '@lexical/utils': 0.20.0 lexical: 0.20.0 - '@lexical/react@0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(yjs@13.6.20)': + '@lexical/react@0.20.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(yjs@13.6.20)': dependencies: '@lexical/clipboard': 0.20.0 '@lexical/code': 0.20.0 - '@lexical/devtools-core': 0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@lexical/devtools-core': 0.20.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@lexical/dragon': 0.20.0 '@lexical/hashtag': 0.20.0 '@lexical/history': 0.20.0 @@ -4515,9 +4568,9 @@ snapshots: '@lexical/utils': 0.20.0 '@lexical/yjs': 0.20.0(yjs@13.6.20) lexical: 0.20.0 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-error-boundary: 3.1.4(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-error-boundary: 3.1.4(react@19.2.1) transitivePeerDependencies: - yjs @@ -4561,12 +4614,12 @@ snapshots: monaco-editor: 0.52.0 state-local: 1.0.7 - '@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: '@monaco-editor/loader': 1.4.0(monaco-editor@0.52.0) monaco-editor: 0.52.0 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) '@mongodb-js/saslprep@1.1.9': dependencies: @@ -4574,32 +4627,34 @@ snapshots: '@next/env@15.0.3': {} + '@next/env@15.5.8': {} + '@next/eslint-plugin-next@15.0.3': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.0.3': + '@next/swc-darwin-arm64@15.5.7': optional: true - '@next/swc-darwin-x64@15.0.3': + '@next/swc-darwin-x64@15.5.7': optional: true - '@next/swc-linux-arm64-gnu@15.0.3': + '@next/swc-linux-arm64-gnu@15.5.7': optional: true - '@next/swc-linux-arm64-musl@15.0.3': + '@next/swc-linux-arm64-musl@15.5.7': optional: true - '@next/swc-linux-x64-gnu@15.0.3': + '@next/swc-linux-x64-gnu@15.5.7': optional: true - '@next/swc-linux-x64-musl@15.0.3': + '@next/swc-linux-x64-musl@15.5.7': optional: true - '@next/swc-win32-arm64-msvc@15.0.3': + '@next/swc-win32-arm64-msvc@15.5.7': optional: true - '@next/swc-win32-x64-msvc@15.0.3': + '@next/swc-win32-x64-msvc@15.5.7': optional: true '@nodelib/fs.scandir@2.1.5': @@ -4616,13 +4671,13 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@payloadcms/db-mongodb@3.2.2(@aws-sdk/credential-providers@3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0)))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))': + '@payloadcms/db-mongodb@3.2.2(@aws-sdk/credential-providers@3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0)))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))': dependencies: http-status: 1.6.2 mongoose: 8.8.1(@aws-sdk/credential-providers@3.699.0(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))) mongoose-aggregate-paginate-v2: 1.1.2 mongoose-paginate-v2: 1.8.5 - payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) prompts: 2.4.2 uuid: 10.0.0 transitivePeerDependencies: @@ -4635,36 +4690,36 @@ snapshots: - socks - supports-color - '@payloadcms/graphql@3.2.2(graphql@16.9.0)(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(typescript@5.5.2)': + '@payloadcms/graphql@3.2.2(graphql@16.9.0)(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(typescript@5.5.2)': dependencies: graphql: 16.9.0 graphql-scalars: 1.22.2(graphql@16.9.0) - payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) pluralize: 8.0.0 ts-essentials: 10.0.3(typescript@5.5.2) tsx: 4.19.2 transitivePeerDependencies: - typescript - '@payloadcms/next@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2)': + '@payloadcms/next@3.2.2(@types/react@19.2.1)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@payloadcms/graphql': 3.2.2(graphql@16.9.0)(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(typescript@5.5.2) + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@payloadcms/graphql': 3.2.2(graphql@16.9.0)(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(typescript@5.5.2) '@payloadcms/translations': 3.2.2 - '@payloadcms/ui': 3.2.2(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + '@payloadcms/ui': 3.2.2(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) busboy: 1.6.0 file-type: 19.3.0 graphql: 16.9.0 graphql-http: 1.22.3(graphql@16.9.0) graphql-playground-html: 1.6.30 http-status: 1.6.2 - next: 15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) path-to-regexp: 6.3.0 - payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) qs-esm: 7.0.2 - react-diff-viewer-continued: 3.2.6(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + react-diff-viewer-continued: 3.2.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) sass: 1.77.4 - sonner: 1.7.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + sonner: 1.7.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -4674,7 +4729,7 @@ snapshots: - supports-color - typescript - '@payloadcms/plugin-cloud@3.0.2(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))': + '@payloadcms/plugin-cloud@3.0.2(@aws-sdk/client-sso-oidc@3.699.0(@aws-sdk/client-sts@3.699.0))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))': dependencies: '@aws-sdk/client-cognito-identity': 3.699.0 '@aws-sdk/client-s3': 3.703.0 @@ -4682,19 +4737,19 @@ snapshots: '@aws-sdk/lib-storage': 3.703.0(@aws-sdk/client-s3@3.703.0) amazon-cognito-identity-js: 6.3.12 nodemailer: 6.9.9 - payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt - encoding - '@payloadcms/plugin-form-builder@3.2.2(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2)': + '@payloadcms/plugin-form-builder@3.2.2(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)': dependencies: - '@payloadcms/ui': 3.2.2(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + '@payloadcms/ui': 3.2.2(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) escape-html: 1.0.3 - payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) transitivePeerDependencies: - '@types/react' - monaco-editor @@ -4702,22 +4757,22 @@ snapshots: - supports-color - typescript - '@payloadcms/richtext-lexical@3.2.2(lzfza3uy2uviaruymssnnecmse)': + '@payloadcms/richtext-lexical@3.2.2(66588668249d7fc5cb26e632554578c6)': dependencies: - '@faceless-ui/modal': 2.0.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@faceless-ui/modal': 2.0.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@lexical/headless': 0.20.0 '@lexical/link': 0.20.0 '@lexical/list': 0.20.0 '@lexical/mark': 0.20.0 - '@lexical/react': 0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(yjs@13.6.20) + '@lexical/react': 0.20.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(yjs@13.6.20) '@lexical/rich-text': 0.20.0 '@lexical/selection': 0.20.0 '@lexical/table': 0.20.0 '@lexical/utils': 0.20.0 - '@payloadcms/next': 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + '@payloadcms/next': 3.2.2(@types/react@19.2.1)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) '@payloadcms/translations': 3.2.2 - '@payloadcms/ui': 3.2.2(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + '@payloadcms/ui': 3.2.2(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -4727,10 +4782,10 @@ snapshots: mdast-util-from-markdown: 2.0.2 mdast-util-mdx-jsx: 3.1.3 micromark-extension-mdx-jsx: 3.0.1 - payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-error-boundary: 4.1.2(react@19.0.0-rc-65a56d0e-20241020) + payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-error-boundary: 4.1.2(react@19.2.1) ts-essentials: 10.0.3(typescript@5.5.2) uuid: 10.0.0 transitivePeerDependencies: @@ -4744,33 +4799,33 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.2.2(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2)': + '@payloadcms/ui@3.2.2(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@payloadcms/translations': 3.2.2 body-scroll-lock: 4.0.0-beta.0 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) object-to-formdata: 4.5.1 - payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2) qs-esm: 7.0.2 - react: 19.0.0-rc-65a56d0e-20241020 - react-datepicker: 6.9.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-image-crop: 10.1.8(react@19.0.0-rc-65a56d0e-20241020) - react-select: 5.8.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + react: 19.2.1 + react-datepicker: 6.9.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react-dom: 19.2.1(react@19.2.1) + react-image-crop: 10.1.8(react@19.2.1) + react-select: 5.8.0(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) scheduler: 0.0.0-experimental-3edc000d-20240926 - sonner: 1.7.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + sonner: 1.7.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) ts-essentials: 10.0.3(typescript@5.5.2) - use-context-selector: 2.0.0(react@19.0.0-rc-65a56d0e-20241020)(scheduler@0.0.0-experimental-3edc000d-20240926) + use-context-selector: 2.0.0(react@19.2.1)(scheduler@0.0.0-experimental-3edc000d-20240926) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -5113,9 +5168,7 @@ snapshots: '@smithy/types': 3.7.1 tslib: 2.8.1 - '@swc/counter@0.1.3': {} - - '@swc/helpers@0.5.13': + '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 @@ -5161,9 +5214,17 @@ snapshots: '@types/parse-json@4.0.2': {} + '@types/react-dom@19.2.1(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 + '@types/react-transition-group@4.4.11': dependencies: - '@types/react': types-react@19.0.0-rc.1 + '@types/react': 19.2.1 + + '@types/react@19.2.1': + dependencies: + csstype: 3.1.3 '@types/unist@2.0.11': {} @@ -5506,18 +5567,6 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - colorette@2.0.20: {} commander@2.20.3: {} @@ -5614,7 +5663,7 @@ snapshots: dequal@2.0.3: {} - detect-libc@2.0.3: + detect-libc@2.1.2: optional: true devlop@1.1.0: @@ -5811,7 +5860,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.17.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.17.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.17.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.3.0 @@ -5824,7 +5873,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.17.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.17.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.17.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -5846,7 +5895,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.17.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.17.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.17.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -6237,9 +6286,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.2: - optional: true - is-async-function@2.0.0: dependencies: has-tostringtag: 1.0.2 @@ -6762,28 +6808,26 @@ snapshots: natural-compare@1.4.0: {} - next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4): + next@15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.0.3 - '@swc/counter': 0.1.3 - '@swc/helpers': 0.5.13 - busboy: 1.6.0 + '@next/env': 15.5.8 + '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001685 postcss: 8.4.31 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - styled-jsx: 5.1.6(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + styled-jsx: 5.1.6(react@19.2.1) optionalDependencies: - '@next/swc-darwin-arm64': 15.0.3 - '@next/swc-darwin-x64': 15.0.3 - '@next/swc-linux-arm64-gnu': 15.0.3 - '@next/swc-linux-arm64-musl': 15.0.3 - '@next/swc-linux-x64-gnu': 15.0.3 - '@next/swc-linux-x64-musl': 15.0.3 - '@next/swc-win32-arm64-msvc': 15.0.3 - '@next/swc-win32-x64-msvc': 15.0.3 + '@next/swc-darwin-arm64': 15.5.7 + '@next/swc-darwin-x64': 15.5.7 + '@next/swc-linux-arm64-gnu': 15.5.7 + '@next/swc-linux-arm64-musl': 15.5.7 + '@next/swc-linux-x64-gnu': 15.5.7 + '@next/swc-linux-x64-musl': 15.5.7 + '@next/swc-win32-arm64-msvc': 15.5.7 + '@next/swc-win32-x64-msvc': 15.5.7 sass: 1.77.4 - sharp: 0.33.5 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -6900,9 +6944,9 @@ snapshots: path-type@4.0.0: {} - payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2): + payload@3.2.2(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.5.2): dependencies: - '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@next/env': 15.0.3 '@payloadcms/translations': 3.2.2 '@types/busboy': 1.5.4 @@ -7032,102 +7076,102 @@ snapshots: quick-format-unescaped@4.0.4: {} - react-datepicker@6.9.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-datepicker@6.9.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - '@floating-ui/react': 0.26.28(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@floating-ui/react': 0.26.28(react-dom@19.2.1(react@19.2.1))(react@19.2.1) clsx: 2.1.1 date-fns: 3.6.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-onclickoutside: 6.13.1(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-onclickoutside: 6.13.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - react-diff-viewer-continued@3.2.6(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-diff-viewer-continued@3.2.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: '@emotion/css': 11.13.5 classnames: 2.5.1 diff: 5.2.0 memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) transitivePeerDependencies: - supports-color - react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020): + react-dom@19.2.1(react@19.2.1): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - scheduler: 0.25.0-rc-65a56d0e-20241020 + react: 19.2.1 + scheduler: 0.27.0 - react-error-boundary@3.1.4(react@19.0.0-rc-65a56d0e-20241020): + react-error-boundary@3.1.4(react@19.2.1): dependencies: '@babel/runtime': 7.26.0 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 - react-error-boundary@4.1.2(react@19.0.0-rc-65a56d0e-20241020): + react-error-boundary@4.1.2(react@19.2.1): dependencies: '@babel/runtime': 7.26.0 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 - react-hook-form@7.53.2(react@19.0.0-rc-65a56d0e-20241020): + react-hook-form@7.53.2(react@19.2.1): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 - react-image-crop@10.1.8(react@19.0.0-rc-65a56d0e-20241020): + react-image-crop@10.1.8(react@19.2.1): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 react-is@16.13.1: {} - react-onclickoutside@6.13.1(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-onclickoutside@6.13.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - react-select@5.8.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1): + react-select@5.10.2(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: '@babel/runtime': 7.26.0 '@emotion/cache': 11.13.5 - '@emotion/react': 11.13.5(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + '@emotion/react': 11.13.5(@types/react@19.2.1)(react@19.2.1) '@floating-ui/dom': 1.6.12 '@types/react-transition-group': 4.4.11 memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-transition-group: 4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - use-isomorphic-layout-effect: 1.1.2(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.1)(react@19.2.1) transitivePeerDependencies: - '@types/react' - supports-color - react-select@5.8.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1): + react-select@5.8.0(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: '@babel/runtime': 7.26.0 '@emotion/cache': 11.13.5 - '@emotion/react': 11.13.5(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + '@emotion/react': 11.13.5(@types/react@19.2.1)(react@19.2.1) '@floating-ui/dom': 1.6.12 '@types/react-transition-group': 4.4.11 memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-transition-group: 4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - use-isomorphic-layout-effect: 1.1.2(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + use-isomorphic-layout-effect: 1.1.2(@types/react@19.2.1)(react@19.2.1) transitivePeerDependencies: - '@types/react' - supports-color - react-transition-group@4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-transition-group@4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: '@babel/runtime': 7.26.0 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) - react@19.0.0-rc-65a56d0e-20241020: {} + react@19.2.1: {} readable-stream@3.6.2: dependencies: @@ -7160,10 +7204,10 @@ snapshots: es-errors: 1.3.0 set-function-name: 2.0.2 - rehackt@0.1.0(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1): + rehackt@0.1.0(@types/react@19.2.1)(react@19.2.1): optionalDependencies: - '@types/react': types-react@19.0.0-rc.1 - react: 19.0.0-rc-65a56d0e-20241020 + '@types/react': 19.2.1 + react: 19.2.1 require-from-string@2.0.2: {} @@ -7224,7 +7268,7 @@ snapshots: scheduler@0.0.0-experimental-3edc000d-20240926: {} - scheduler@0.25.0-rc-65a56d0e-20241020: {} + scheduler@0.27.0: {} scmp@2.1.0: {} @@ -7234,6 +7278,9 @@ snapshots: semver@7.6.3: {} + semver@7.7.3: + optional: true + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -7250,31 +7297,36 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 - sharp@0.33.5: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.3 - semver: 7.6.3 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -7292,11 +7344,6 @@ snapshots: sift@17.1.3: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - simple-wcswidth@1.0.1: {} sisteransi@1.0.5: {} @@ -7305,10 +7352,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@1.7.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + sonner@1.7.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) source-map-js@1.2.1: {} @@ -7398,10 +7445,10 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.3.1 - styled-jsx@5.1.6(react@19.0.0-rc-65a56d0e-20241020): + styled-jsx@5.1.6(react@19.2.1): dependencies: client-only: 0.0.1 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 stylis@4.2.0: {} @@ -7518,14 +7565,6 @@ snapshots: possible-typed-array-names: 1.0.0 reflect.getprototypeof: 1.0.7 - types-react-dom@19.0.0-rc.1: - dependencies: - '@types/react': types-react@19.0.0-rc.1 - - types-react@19.0.0-rc.1: - dependencies: - csstype: 3.1.3 - typescript@5.5.2: {} uint8array-extras@1.4.0: {} @@ -7568,16 +7607,22 @@ snapshots: dependencies: punycode: 2.3.1 - use-context-selector@2.0.0(react@19.0.0-rc-65a56d0e-20241020)(scheduler@0.0.0-experimental-3edc000d-20240926): + use-context-selector@2.0.0(react@19.2.1)(scheduler@0.0.0-experimental-3edc000d-20240926): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 scheduler: 0.0.0-experimental-3edc000d-20240926 - use-isomorphic-layout-effect@1.1.2(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1): + use-isomorphic-layout-effect@1.1.2(@types/react@19.2.1)(react@19.2.1): + dependencies: + react: 19.2.1 + optionalDependencies: + '@types/react': 19.2.1 + + use-isomorphic-layout-effect@1.2.1(@types/react@19.2.1)(react@19.2.1): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.1 optionalDependencies: - '@types/react': types-react@19.0.0-rc.1 + '@types/react': 19.2.1 utf8-byte-length@1.0.5: {} diff --git a/examples/live-preview/package.json b/examples/live-preview/package.json index 9052a2c2827..62a0cb59b47 100644 --- a/examples/live-preview/package.json +++ b/examples/live-preview/package.json @@ -27,7 +27,7 @@ "dotenv": "^8.2.0", "escape-html": "^1.0.3", "graphql": "^16.9.0", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1", diff --git a/examples/live-preview/pnpm-lock.yaml b/examples/live-preview/pnpm-lock.yaml index ba419e95af2..35f1734b29a 100644 --- a/examples/live-preview/pnpm-lock.yaml +++ b/examples/live-preview/pnpm-lock.yaml @@ -13,16 +13,16 @@ importers: version: 3.39.1(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2)) '@payloadcms/live-preview-react': specifier: latest - version: 3.39.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 3.39.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/next': specifier: latest - version: 3.39.1(@types/react@19.0.1)(graphql@16.11.0)(monaco-editor@0.52.2)(next@15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.39.1(@types/react@19.2.1)(graphql@16.11.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@payloadcms/richtext-slate': specifier: latest - version: 3.39.1(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.39.1(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@payloadcms/ui': specifier: latest - version: 3.39.1(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.39.1(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -36,20 +36,20 @@ importers: specifier: ^16.9.0 version: 16.11.0 next: - specifier: ^15.2.3 - version: 15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + specifier: ^15.4.9 + version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest version: 3.39.1(graphql@16.11.0)(typescript@5.5.2) react: - specifier: 19.0.0 - version: 19.0.0 + specifier: ^19.2.1 + version: 19.2.2 react-dom: - specifier: 19.0.0 - version: 19.0.0(react@19.0.0) + specifier: ^19.2.1 + version: 19.2.2(react@19.2.2) react-hook-form: specifier: ^7.51.3 - version: 7.56.4(react@19.0.0) + version: 7.56.4(react@19.2.2) devDependencies: '@payloadcms/graphql': specifier: latest @@ -67,11 +67,11 @@ importers: specifier: ^20.11.25 version: 20.17.50 '@types/react': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1 '@types/react-dom': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -166,6 +166,9 @@ packages: '@emnapi/runtime@1.4.3': resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/wasi-threads@1.0.2': resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} @@ -577,118 +580,139 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead - '@img/sharp-darwin-arm64@0.34.2': - resolution: {integrity: sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.2': - resolution: {integrity: sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.1.0': - resolution: {integrity: sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.1.0': - resolution: {integrity: sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.1.0': - resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.1.0': - resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-ppc64@1.1.0': - resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] - '@img/sharp-libvips-linux-s390x@1.1.0': - resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==} + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.1.0': - resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.1.0': - resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.1.0': - resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.34.2': - resolution: {integrity: sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.34.2': - resolution: {integrity: sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.34.2': - resolution: {integrity: sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.34.2': - resolution: {integrity: sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.34.2': - resolution: {integrity: sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.34.2': - resolution: {integrity: sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.34.2': - resolution: {integrity: sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.2': - resolution: {integrity: sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.2': - resolution: {integrity: sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==} + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.2': - resolution: {integrity: sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -736,53 +760,56 @@ packages: '@next/env@15.3.2': resolution: {integrity: sha512-xURk++7P7qR9JG1jJtLzPzf0qEvqCN0A/T3DXf8IPMKo9/6FfjxtEffRJIIew/bIL4T3C2jLLqBor8B/zVlx6g==} + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + '@next/eslint-plugin-next@15.3.2': resolution: {integrity: sha512-ijVRTXBgnHT33aWnDtmlG+LJD+5vhc9AKTJPquGG5NKXjpKNjc62woIhFtrAcWdBobt8kqjCoaJ0q6sDQoX7aQ==} - '@next/swc-darwin-arm64@15.3.2': - resolution: {integrity: sha512-2DR6kY/OGcokbnCsjHpNeQblqCZ85/1j6njYSkzRdpLn5At7OkSdmk7WyAmB9G0k25+VgqVZ/u356OSoQZ3z0g==} + '@next/swc-darwin-arm64@15.5.7': + resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.3.2': - resolution: {integrity: sha512-ro/fdqaZWL6k1S/5CLv1I0DaZfDVJkWNaUU3un8Lg6m0YENWlDulmIWzV96Iou2wEYyEsZq51mwV8+XQXqMp3w==} + '@next/swc-darwin-x64@15.5.7': + resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.3.2': - resolution: {integrity: sha512-covwwtZYhlbRWK2HlYX9835qXum4xYZ3E2Mra1mdQ+0ICGoMiw1+nVAn4d9Bo7R3JqSmK1grMq/va+0cdh7bJA==} + '@next/swc-linux-arm64-gnu@15.5.7': + resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.3.2': - resolution: {integrity: sha512-KQkMEillvlW5Qk5mtGA/3Yz0/tzpNlSw6/3/ttsV1lNtMuOHcGii3zVeXZyi4EJmmLDKYcTcByV2wVsOhDt/zg==} + '@next/swc-linux-arm64-musl@15.5.7': + resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.3.2': - resolution: {integrity: sha512-uRBo6THWei0chz+Y5j37qzx+BtoDRFIkDzZjlpCItBRXyMPIg079eIkOCl3aqr2tkxL4HFyJ4GHDes7W8HuAUg==} + '@next/swc-linux-x64-gnu@15.5.7': + resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.3.2': - resolution: {integrity: sha512-+uxFlPuCNx/T9PdMClOqeE8USKzj8tVz37KflT3Kdbx/LOlZBRI2yxuIcmx1mPNK8DwSOMNCr4ureSet7eyC0w==} + '@next/swc-linux-x64-musl@15.5.7': + resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.3.2': - resolution: {integrity: sha512-LLTKmaI5cfD8dVzh5Vt7+OMo+AIOClEdIU/TSKbXXT2iScUTSxOGoBhfuv+FU8R9MLmrkIL1e2fBMkEEjYAtPQ==} + '@next/swc-win32-arm64-msvc@15.5.7': + resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.3.2': - resolution: {integrity: sha512-aW5B8wOPioJ4mBdMDXkt5f3j8pUr9W8AnlX0Df35uRWNT1Y6RIybxjnSUe+PhM+M1bwgyY8PHLmXZC6zT1o5tA==} + '@next/swc-win32-x64-msvc@15.5.7': + resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -965,16 +992,18 @@ packages: '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/react-dom@19.0.1': - resolution: {integrity: sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 '@types/react-transition-group@4.4.12': resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} peerDependencies: '@types/react': '*' - '@types/react@19.0.1': - resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} '@types/webidl-conversions@7.0.3': resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} @@ -1293,13 +1322,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -1407,8 +1429,8 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} diff@5.2.0: @@ -1853,9 +1875,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -2164,13 +2183,13 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.3.2: - resolution: {integrity: sha512-CA3BatMyHkxZ48sgOCLdVHjFU36N7TF1HhqAHLFOkV6buwZnvMI84Cug8xD56B9mCuKrqXnLn94417GrZ/jjCQ==} + next@15.5.8: + resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 + '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 @@ -2374,10 +2393,10 @@ packages: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom@19.0.0: - resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + react-dom@19.2.2: + resolution: {integrity: sha512-fhyD2BLrew6qYf4NNtHff1rLXvzR25rq49p+FeqByOazc6TcSi2n8EYulo5C1PbH+1uBW++5S1SG7FcUU6mlDg==} peerDependencies: - react: ^19.0.0 + react: ^19.2.2 react-hook-form@7.56.4: resolution: {integrity: sha512-Rob7Ftz2vyZ/ZGsQZPaRdIefkgOSrQSPXfqBdvOPwJfoGnjwRJUs7EM7Kc1mcoDv3NOtqBzPGbcMB8CGn9CKgw==} @@ -2405,8 +2424,8 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' - react@19.0.0: - resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} + react@19.2.2: + resolution: {integrity: sha512-BdOGOY8OKRBcgoDkwqA8Q5XvOIhoNx/Sh6BnGJlet2Abt0X5BK0BDrqGyQgLhAVjD2nAg5f6o01u/OPUhG022Q==} engines: {node: '>=0.10.0'} readdirp@3.6.0: @@ -2484,6 +2503,9 @@ packages: scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + scmp@2.1.0: resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} @@ -2502,6 +2524,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2514,8 +2541,8 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} - sharp@0.34.2: - resolution: {integrity: sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -2545,9 +2572,6 @@ packages: sift@17.1.3: resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - simple-wcswidth@1.0.1: resolution: {integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==} @@ -2931,29 +2955,29 @@ snapshots: '@date-fns/tz@1.2.0': {} - '@dnd-kit/accessibility@3.1.1(react@19.0.0)': + '@dnd-kit/accessibility@3.1.1(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@dnd-kit/accessibility': 3.1.1(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tslib: 2.8.1 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.0.0)': + '@dnd-kit/utilities@3.2.2(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 '@emnapi/core@1.4.3': @@ -2967,6 +2991,11 @@ snapshots: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/wasi-threads@1.0.2': dependencies: tslib: 2.8.1 @@ -3010,19 +3039,19 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.0.1)(react@19.0.0)': + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.2)': dependencies: '@babel/runtime': 7.27.3 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.0.0) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.2) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 transitivePeerDependencies: - supports-color @@ -3038,9 +3067,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.0.0)': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 '@emotion/utils@1.4.2': {} @@ -3216,23 +3245,23 @@ snapshots: '@eslint/js@8.57.1': {} - '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: body-scroll-lock: 4.0.0-beta.0 focus-trap: 7.5.4 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) - '@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@faceless-ui/window-info@3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/window-info@3.0.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@floating-ui/core@1.7.0': dependencies: @@ -3243,18 +3272,18 @@ snapshots: '@floating-ui/core': 1.7.0 '@floating-ui/utils': 0.2.9 - '@floating-ui/react-dom@2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react-dom@2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@floating-ui/dom': 1.7.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@floating-ui/react@0.27.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react@0.27.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react-dom': 2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@floating-ui/utils': 0.2.9 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tabbable: 6.2.0 '@floating-ui/utils@0.2.9': {} @@ -3271,85 +3300,101 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@img/sharp-darwin-arm64@0.34.2': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.1.0 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.34.2': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.1.0 + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.1.0': + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.1.0': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.1.0': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.1.0': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-ppc64@1.1.0': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.1.0': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.1.0': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.1.0': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.1.0': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - '@img/sharp-linux-arm64@0.34.2': + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.1.0 + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-arm@0.34.2': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.1.0 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.34.2': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.1.0 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-x64@0.34.2': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.1.0 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.34.2': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.34.2': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.1.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-wasm32@0.34.2': + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.4.3 + '@emnapi/runtime': 1.7.1 optional: true - '@img/sharp-win32-arm64@0.34.2': + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-ia32@0.34.2': + '@img/sharp-win32-ia32@0.34.5': optional: true - '@img/sharp-win32-x64@0.34.2': + '@img/sharp-win32-x64@0.34.5': optional: true '@jridgewell/gen-mapping@0.3.8': @@ -3377,12 +3422,12 @@ snapshots: dependencies: state-local: 1.0.7 - '@monaco-editor/react@4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@monaco-editor/react@4.7.0(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@monaco-editor/loader': 1.5.0 monaco-editor: 0.52.2 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@mongodb-js/saslprep@1.2.2': dependencies: @@ -3397,32 +3442,34 @@ snapshots: '@next/env@15.3.2': {} + '@next/env@15.5.8': {} + '@next/eslint-plugin-next@15.3.2': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.3.2': + '@next/swc-darwin-arm64@15.5.7': optional: true - '@next/swc-darwin-x64@15.3.2': + '@next/swc-darwin-x64@15.5.7': optional: true - '@next/swc-linux-arm64-gnu@15.3.2': + '@next/swc-linux-arm64-gnu@15.5.7': optional: true - '@next/swc-linux-arm64-musl@15.3.2': + '@next/swc-linux-arm64-musl@15.5.7': optional: true - '@next/swc-linux-x64-gnu@15.3.2': + '@next/swc-linux-x64-gnu@15.5.7': optional: true - '@next/swc-linux-x64-musl@15.3.2': + '@next/swc-linux-x64-musl@15.5.7': optional: true - '@next/swc-win32-arm64-msvc@15.3.2': + '@next/swc-win32-arm64-msvc@15.5.7': optional: true - '@next/swc-win32-x64-msvc@15.3.2': + '@next/swc-win32-x64-msvc@15.5.7': optional: true '@nodelib/fs.scandir@2.1.5': @@ -3467,20 +3514,20 @@ snapshots: transitivePeerDependencies: - typescript - '@payloadcms/live-preview-react@3.39.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@payloadcms/live-preview-react@3.39.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@payloadcms/live-preview': 3.39.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@payloadcms/live-preview@3.39.1': {} - '@payloadcms/next@3.39.1(@types/react@19.0.1)(graphql@16.11.0)(monaco-editor@0.52.2)(next@15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/next@3.39.1(@types/react@19.2.1)(graphql@16.11.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/graphql': 3.39.1(graphql@16.11.0)(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(typescript@5.5.2) '@payloadcms/translations': 3.39.1 - '@payloadcms/ui': 3.39.1(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/ui': 3.39.1(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) busboy: 1.6.0 dequal: 2.0.3 file-type: 19.3.0 @@ -3488,11 +3535,11 @@ snapshots: graphql-http: 1.22.4(graphql@16.11.0) graphql-playground-html: 1.6.30 http-status: 2.1.0 - next: 15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) path-to-regexp: 6.3.0 payload: 3.39.1(graphql@16.11.0)(typescript@5.5.2) qs-esm: 7.0.2 - react-diff-viewer-continued: 4.0.5(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-diff-viewer-continued: 4.0.5(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) sass: 1.77.4 uuid: 10.0.0 transitivePeerDependencies: @@ -3503,17 +3550,17 @@ snapshots: - supports-color - typescript - '@payloadcms/richtext-slate@3.39.1(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/richtext-slate@3.39.1(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: '@payloadcms/translations': 3.39.1 - '@payloadcms/ui': 3.39.1(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/ui': 3.39.1(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) is-hotkey: 0.2.0 payload: 3.39.1(graphql@16.11.0)(typescript@5.5.2) - react: 19.0.0 + react: 19.2.2 slate: 0.91.4 slate-history: 0.86.0(slate@0.91.4) slate-hyperscript: 0.81.3(slate@0.91.4) - slate-react: 0.92.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(slate@0.91.4) + slate-react: 0.92.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(slate@0.91.4) transitivePeerDependencies: - '@types/react' - monaco-editor @@ -3526,34 +3573,34 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.39.1(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/ui@3.39.1(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.39.1(graphql@16.11.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: '@date-fns/tz': 1.2.0 - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/scroll-info': 2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/window-info': 3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@monaco-editor/react': 4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/window-info': 3.0.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@monaco-editor/react': 4.7.0(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/translations': 3.39.1 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) object-to-formdata: 4.5.1 payload: 3.39.1(graphql@16.11.0)(typescript@5.5.2) qs-esm: 7.0.2 - react: 19.0.0 - react-datepicker: 7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-dom: 19.0.0(react@19.0.0) - react-image-crop: 10.1.8(react@19.0.0) - react-select: 5.9.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.2 + react-datepicker: 7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-dom: 19.2.2(react@19.2.2) + react-image-crop: 10.1.8(react@19.2.2) + react-select: 5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) scheduler: 0.25.0 - sonner: 1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + sonner: 1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2) ts-essentials: 10.0.3(typescript@5.5.2) - use-context-selector: 2.0.0(react@19.0.0)(scheduler@0.25.0) + use-context-selector: 2.0.0(react@19.2.2)(scheduler@0.25.0) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -3648,15 +3695,15 @@ snapshots: '@types/parse-json@4.0.2': {} - '@types/react-dom@19.0.1': + '@types/react-dom@19.2.1(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@types/react-transition-group@4.4.12(@types/react@19.0.1)': + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@types/react@19.0.1': + '@types/react@19.2.1': dependencies: csstype: 3.1.3 @@ -3999,18 +4046,6 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - optional: true - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - optional: true - colorette@2.0.20: {} commander@2.20.3: {} @@ -4105,7 +4140,7 @@ snapshots: dequal@2.0.3: {} - detect-libc@2.0.4: + detect-libc@2.1.2: optional: true diff@5.2.0: {} @@ -4740,9 +4775,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.2: - optional: true - is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -5030,28 +5062,26 @@ snapshots: natural-compare@1.4.0: {} - next@15.3.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): + next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): dependencies: - '@next/env': 15.3.2 - '@swc/counter': 0.1.3 + '@next/env': 15.5.8 '@swc/helpers': 0.5.15 - busboy: 1.6.0 caniuse-lite: 1.0.30001718 postcss: 8.4.31 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + styled-jsx: 5.1.6(react@19.2.2) optionalDependencies: - '@next/swc-darwin-arm64': 15.3.2 - '@next/swc-darwin-x64': 15.3.2 - '@next/swc-linux-arm64-gnu': 15.3.2 - '@next/swc-linux-arm64-musl': 15.3.2 - '@next/swc-linux-x64-gnu': 15.3.2 - '@next/swc-linux-x64-musl': 15.3.2 - '@next/swc-win32-arm64-msvc': 15.3.2 - '@next/swc-win32-x64-msvc': 15.3.2 + '@next/swc-darwin-arm64': 15.5.7 + '@next/swc-darwin-x64': 15.5.7 + '@next/swc-linux-arm64-gnu': 15.5.7 + '@next/swc-linux-arm64-musl': 15.5.7 + '@next/swc-linux-x64-gnu': 15.5.7 + '@next/swc-linux-x64-musl': 15.5.7 + '@next/swc-win32-arm64-msvc': 15.5.7 + '@next/swc-win32-x64-msvc': 15.5.7 sass: 1.77.4 - sharp: 0.34.2 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -5275,69 +5305,69 @@ snapshots: quick-format-unescaped@4.0.4: {} - react-datepicker@7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-datepicker@7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - '@floating-ui/react': 0.27.9(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react': 0.27.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2) clsx: 2.1.1 date-fns: 3.6.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react-diff-viewer-continued@4.0.5(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-diff-viewer-continued@4.0.5(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@emotion/css': 11.13.5 - '@emotion/react': 11.14.0(@types/react@19.0.1)(react@19.0.0) + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.2) classnames: 2.5.1 diff: 5.2.0 memoize-one: 6.0.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) transitivePeerDependencies: - '@types/react' - supports-color - react-dom@19.0.0(react@19.0.0): + react-dom@19.2.2(react@19.2.2): dependencies: - react: 19.0.0 - scheduler: 0.25.0 + react: 19.2.2 + scheduler: 0.27.0 - react-hook-form@7.56.4(react@19.0.0): + react-hook-form@7.56.4(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 - react-image-crop@10.1.8(react@19.0.0): + react-image-crop@10.1.8(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 react-is@16.13.1: {} - react-select@5.9.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-select@5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.27.3 '@emotion/cache': 11.14.0 - '@emotion/react': 11.14.0(@types/react@19.0.1)(react@19.0.0) + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.2) '@floating-ui/dom': 1.7.0 - '@types/react-transition-group': 4.4.12(@types/react@19.0.1) + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - use-isomorphic-layout-effect: 1.2.1(@types/react@19.0.1)(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.1)(react@19.2.2) transitivePeerDependencies: - '@types/react' - supports-color - react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-transition-group@4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.27.3 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react@19.0.0: {} + react@19.2.2: {} readdirp@3.6.0: dependencies: @@ -5426,6 +5456,8 @@ snapshots: scheduler@0.25.0: {} + scheduler@0.27.0: {} + scmp@2.1.0: {} scroll-into-view-if-needed@2.2.31: @@ -5438,6 +5470,9 @@ snapshots: semver@7.7.2: {} + semver@7.7.3: + optional: true + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5460,33 +5495,36 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 - sharp@0.34.2: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.4 - semver: 7.7.2 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.2 - '@img/sharp-darwin-x64': 0.34.2 - '@img/sharp-libvips-darwin-arm64': 1.1.0 - '@img/sharp-libvips-darwin-x64': 1.1.0 - '@img/sharp-libvips-linux-arm': 1.1.0 - '@img/sharp-libvips-linux-arm64': 1.1.0 - '@img/sharp-libvips-linux-ppc64': 1.1.0 - '@img/sharp-libvips-linux-s390x': 1.1.0 - '@img/sharp-libvips-linux-x64': 1.1.0 - '@img/sharp-libvips-linuxmusl-arm64': 1.1.0 - '@img/sharp-libvips-linuxmusl-x64': 1.1.0 - '@img/sharp-linux-arm': 0.34.2 - '@img/sharp-linux-arm64': 0.34.2 - '@img/sharp-linux-s390x': 0.34.2 - '@img/sharp-linux-x64': 0.34.2 - '@img/sharp-linuxmusl-arm64': 0.34.2 - '@img/sharp-linuxmusl-x64': 0.34.2 - '@img/sharp-wasm32': 0.34.2 - '@img/sharp-win32-arm64': 0.34.2 - '@img/sharp-win32-ia32': 0.34.2 - '@img/sharp-win32-x64': 0.34.2 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -5525,11 +5563,6 @@ snapshots: sift@17.1.3: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - optional: true - simple-wcswidth@1.0.1: {} sisteransi@1.0.5: {} @@ -5544,7 +5577,7 @@ snapshots: is-plain-object: 5.0.0 slate: 0.91.4 - slate-react@0.92.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(slate@0.91.4): + slate-react@0.92.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(slate@0.91.4): dependencies: '@juggle/resize-observer': 3.4.0 '@types/is-hotkey': 0.1.10 @@ -5553,8 +5586,8 @@ snapshots: is-hotkey: 0.1.8 is-plain-object: 5.0.0 lodash: 4.17.21 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) scroll-into-view-if-needed: 2.2.31 slate: 0.91.4 tiny-invariant: 1.0.6 @@ -5575,10 +5608,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + sonner@1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) source-map-js@1.2.1: {} @@ -5659,10 +5692,10 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.4.2 - styled-jsx@5.1.6(react@19.0.0): + styled-jsx@5.1.6(react@19.2.2): dependencies: client-only: 0.0.1 - react: 19.0.0 + react: 19.2.2 stylis@4.2.0: {} @@ -5815,16 +5848,16 @@ snapshots: dependencies: punycode: 2.3.1 - use-context-selector@2.0.0(react@19.0.0)(scheduler@0.25.0): + use-context-selector@2.0.0(react@19.2.2)(scheduler@0.25.0): dependencies: - react: 19.0.0 + react: 19.2.2 scheduler: 0.25.0 - use-isomorphic-layout-effect@1.2.1(@types/react@19.0.1)(react@19.0.0): + use-isomorphic-layout-effect@1.2.1(@types/react@19.2.1)(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 utf8-byte-length@1.0.5: {} diff --git a/examples/localization/package.json b/examples/localization/package.json index 847978f4ae0..3153b964a1f 100644 --- a/examples/localization/package.json +++ b/examples/localization/package.json @@ -39,7 +39,7 @@ "graphql": "^16.8.2", "jsonwebtoken": "9.0.2", "lucide-react": "^0.378.0", - "next": "^15.4.8", + "next": "^15.4.9", "next-intl": "^3.23.2", "payload": "latest", "prism-react-renderer": "^2.3.1", diff --git a/examples/localization/pnpm-lock.yaml b/examples/localization/pnpm-lock.yaml index 57c7ba75fb7..db6c9cc82ef 100644 --- a/examples/localization/pnpm-lock.yaml +++ b/examples/localization/pnpm-lock.yaml @@ -13,16 +13,16 @@ importers: version: 3.25.0(@aws-sdk/credential-providers@3.758.0)(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3)) '@payloadcms/live-preview-react': specifier: latest - version: 3.25.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 3.25.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/next': specifier: latest - version: 3.25.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + version: 3.25.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) '@payloadcms/payload-cloud': specifier: latest version: 3.25.0(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3)) '@payloadcms/plugin-form-builder': specifier: latest - version: 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + version: 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) '@payloadcms/plugin-nested-docs': specifier: latest version: 3.25.0(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3)) @@ -31,28 +31,28 @@ importers: version: 3.25.0(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3)) '@payloadcms/plugin-search': specifier: latest - version: 3.25.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + version: 3.25.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) '@payloadcms/plugin-seo': specifier: latest - version: 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + version: 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) '@payloadcms/richtext-lexical': specifier: latest - version: 3.25.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.25.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.23) + version: 3.25.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.25.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3))(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)(yjs@13.6.23) '@payloadcms/ui': specifier: latest - version: 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + version: 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) '@radix-ui/react-checkbox': specifier: ^1.0.4 - version: 1.1.4(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 1.1.4(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@radix-ui/react-label': specifier: ^2.0.2 - version: 2.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 2.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@radix-ui/react-select': specifier: ^2.0.0 - version: 2.1.6(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: 2.1.6(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@radix-ui/react-slot': specifier: ^1.0.2 - version: 1.1.2(@types/react@19.0.1)(react@19.0.0) + version: 1.1.2(@types/react@19.2.1)(react@19.2.2) class-variance-authority: specifier: ^0.7.0 version: 0.7.1 @@ -64,7 +64,7 @@ importers: version: 7.0.3 geist: specifier: ^1.3.0 - version: 1.3.1(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)) + version: 1.3.1(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4)) graphql: specifier: ^16.8.2 version: 16.10.0 @@ -73,28 +73,28 @@ importers: version: 9.0.2 lucide-react: specifier: ^0.378.0 - version: 0.378.0(react@19.0.0) + version: 0.378.0(react@19.2.2) next: - specifier: ^15.2.3 - version: 15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + specifier: ^15.4.9 + version: 15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) next-intl: specifier: ^3.23.2 - version: 3.26.5(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0) + version: 3.26.5(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(react@19.2.2) payload: specifier: latest version: 3.25.0(graphql@16.10.0)(typescript@5.7.3) prism-react-renderer: specifier: ^2.3.1 - version: 2.4.1(react@19.0.0) + version: 2.4.1(react@19.2.2) react: - specifier: ^19.0.0 - version: 19.0.0 + specifier: ^19.2.1 + version: 19.2.2 react-dom: - specifier: ^19.0.0 - version: 19.0.0(react@19.0.0) + specifier: ^19.2.1 + version: 19.2.2(react@19.2.2) react-hook-form: specifier: 7.45.4 - version: 7.45.4(react@19.0.0) + version: 7.45.4(react@19.2.2) sharp: specifier: 0.32.6 version: 0.32.6 @@ -121,11 +121,11 @@ importers: specifier: 22.5.4 version: 22.5.4 '@types/react': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1 '@types/react-dom': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) autoprefixer: specifier: ^10.4.19 version: 10.4.20(postcss@8.5.3) @@ -1675,16 +1675,18 @@ packages: '@types/prismjs@1.26.5': resolution: {integrity: sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==} - '@types/react-dom@19.0.1': - resolution: {integrity: sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 '@types/react-transition-group@4.4.12': resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} peerDependencies: '@types/react': '*' - '@types/react@19.0.1': - resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -3222,6 +3224,7 @@ packages: next@15.5.4: resolution: {integrity: sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -3550,10 +3553,10 @@ packages: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom@19.0.0: - resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + react-dom@19.2.2: + resolution: {integrity: sha512-fhyD2BLrew6qYf4NNtHff1rLXvzR25rq49p+FeqByOazc6TcSi2n8EYulo5C1PbH+1uBW++5S1SG7FcUU6mlDg==} peerDependencies: - react: ^19.0.0 + react: ^19.2.2 react-error-boundary@3.1.4: resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} @@ -3622,8 +3625,8 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' - react@19.0.0: - resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} + react@19.2.2: + resolution: {integrity: sha512-BdOGOY8OKRBcgoDkwqA8Q5XvOIhoNx/Sh6BnGJlet2Abt0X5BK0BDrqGyQgLhAVjD2nAg5f6o01u/OPUhG022Q==} engines: {node: '>=0.10.0'} read-cache@1.0.0: @@ -3722,6 +3725,9 @@ packages: scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + scmp@2.1.0: resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} @@ -4908,29 +4914,29 @@ snapshots: '@date-fns/tz@1.2.0': {} - '@dnd-kit/accessibility@3.1.1(react@19.0.0)': + '@dnd-kit/accessibility@3.1.1(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@dnd-kit/accessibility': 3.1.1(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tslib: 2.8.1 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.0.0)': + '@dnd-kit/utilities@3.2.2(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 '@emnapi/runtime@1.5.0': @@ -4976,19 +4982,19 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.0.1)(react@19.0.0)': + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.2)': dependencies: '@babel/runtime': 7.26.9 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.0.0) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.2) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 transitivePeerDependencies: - supports-color @@ -5004,9 +5010,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.0.0)': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 '@emotion/utils@1.4.2': {} @@ -5126,23 +5132,23 @@ snapshots: '@eslint/core': 0.12.0 levn: 0.4.1 - '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: body-scroll-lock: 4.0.0-beta.0 focus-trap: 7.5.4 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) - '@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@faceless-ui/window-info@3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/window-info@3.0.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@floating-ui/core@1.6.9': dependencies: @@ -5153,18 +5159,18 @@ snapshots: '@floating-ui/core': 1.6.9 '@floating-ui/utils': 0.2.9 - '@floating-ui/react-dom@2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react-dom@2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@floating-ui/dom': 1.6.13 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@floating-ui/react@0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react@0.27.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react-dom': 2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@floating-ui/utils': 0.2.9 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tabbable: 6.2.0 '@floating-ui/utils@0.2.9': {} @@ -5343,7 +5349,7 @@ snapshots: lexical: 0.21.0 prismjs: 1.29.0 - '@lexical/devtools-core@0.21.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@lexical/devtools-core@0.21.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@lexical/html': 0.21.0 '@lexical/link': 0.21.0 @@ -5351,8 +5357,8 @@ snapshots: '@lexical/table': 0.21.0 '@lexical/utils': 0.21.0 lexical: 0.21.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@lexical/dragon@0.21.0': dependencies: @@ -5418,11 +5424,11 @@ snapshots: '@lexical/utils': 0.21.0 lexical: 0.21.0 - '@lexical/react@0.21.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(yjs@13.6.23)': + '@lexical/react@0.21.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.23)': dependencies: '@lexical/clipboard': 0.21.0 '@lexical/code': 0.21.0 - '@lexical/devtools-core': 0.21.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@lexical/devtools-core': 0.21.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@lexical/dragon': 0.21.0 '@lexical/hashtag': 0.21.0 '@lexical/history': 0.21.0 @@ -5439,9 +5445,9 @@ snapshots: '@lexical/utils': 0.21.0 '@lexical/yjs': 0.21.0(yjs@13.6.23) lexical: 0.21.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-error-boundary: 3.1.4(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 3.1.4(react@19.2.2) transitivePeerDependencies: - yjs @@ -5484,12 +5490,12 @@ snapshots: dependencies: state-local: 1.0.7 - '@monaco-editor/react@4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@monaco-editor/react@4.7.0(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@monaco-editor/loader': 1.5.0 monaco-editor: 0.52.2 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@mongodb-js/saslprep@1.2.0': dependencies: @@ -5575,20 +5581,20 @@ snapshots: transitivePeerDependencies: - typescript - '@payloadcms/live-preview-react@3.25.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@payloadcms/live-preview-react@3.25.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@payloadcms/live-preview': 3.25.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@payloadcms/live-preview@3.25.0': {} - '@payloadcms/next@3.25.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/next@3.25.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/graphql': 3.25.0(graphql@16.10.0)(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(typescript@5.7.3) '@payloadcms/translations': 3.25.0 - '@payloadcms/ui': 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/ui': 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) busboy: 1.6.0 dequal: 2.0.3 file-type: 19.3.0 @@ -5596,11 +5602,11 @@ snapshots: graphql-http: 1.22.4(graphql@16.10.0) graphql-playground-html: 1.6.30 http-status: 2.1.0 - next: 15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) path-to-regexp: 6.3.0 payload: 3.25.0(graphql@16.10.0)(typescript@5.7.3) qs-esm: 7.0.2 - react-diff-viewer-continued: 4.0.4(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-diff-viewer-continued: 4.0.4(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) sass: 1.77.4 uuid: 10.0.0 transitivePeerDependencies: @@ -5625,13 +5631,13 @@ snapshots: - aws-crt - encoding - '@payloadcms/plugin-form-builder@3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/plugin-form-builder@3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)': dependencies: - '@payloadcms/ui': 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/ui': 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) escape-html: 1.0.3 payload: 3.25.0(graphql@16.10.0)(typescript@5.7.3) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) transitivePeerDependencies: - '@types/react' - monaco-editor @@ -5647,13 +5653,13 @@ snapshots: dependencies: payload: 3.25.0(graphql@16.10.0)(typescript@5.7.3) - '@payloadcms/plugin-search@3.25.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/plugin-search@3.25.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)': dependencies: - '@payloadcms/next': 3.25.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) - '@payloadcms/ui': 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/next': 3.25.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) + '@payloadcms/ui': 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) payload: 3.25.0(graphql@16.10.0)(typescript@5.7.3) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) transitivePeerDependencies: - '@types/react' - graphql @@ -5662,13 +5668,13 @@ snapshots: - supports-color - typescript - '@payloadcms/plugin-seo@3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/plugin-seo@3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)': dependencies: '@payloadcms/translations': 3.25.0 - '@payloadcms/ui': 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/ui': 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) payload: 3.25.0(graphql@16.10.0)(typescript@5.7.3) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) transitivePeerDependencies: - '@types/react' - monaco-editor @@ -5676,23 +5682,23 @@ snapshots: - supports-color - typescript - '@payloadcms/richtext-lexical@3.25.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.25.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.23)': + '@payloadcms/richtext-lexical@3.25.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.25.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3))(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)(yjs@13.6.23)': dependencies: - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/scroll-info': 2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@lexical/headless': 0.21.0 '@lexical/html': 0.21.0 '@lexical/link': 0.21.0 '@lexical/list': 0.21.0 '@lexical/mark': 0.21.0 - '@lexical/react': 0.21.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(yjs@13.6.23) + '@lexical/react': 0.21.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.23) '@lexical/rich-text': 0.21.0 '@lexical/selection': 0.21.0 '@lexical/table': 0.21.0 '@lexical/utils': 0.21.0 - '@payloadcms/next': 3.25.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/next': 3.25.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) '@payloadcms/translations': 3.25.0 - '@payloadcms/ui': 3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3) + '@payloadcms/ui': 3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -5704,9 +5710,9 @@ snapshots: mdast-util-mdx-jsx: 3.1.3 micromark-extension-mdx-jsx: 3.0.1 payload: 3.25.0(graphql@16.10.0)(typescript@5.7.3) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-error-boundary: 4.1.2(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 4.1.2(react@19.2.2) ts-essentials: 10.0.3(typescript@5.7.3) uuid: 10.0.0 transitivePeerDependencies: @@ -5721,33 +5727,33 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.25.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)': + '@payloadcms/ui@3.25.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.25.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)': dependencies: '@date-fns/tz': 1.2.0 - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/scroll-info': 2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/window-info': 3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@monaco-editor/react': 4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/window-info': 3.0.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@monaco-editor/react': 4.7.0(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/translations': 3.25.0 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) object-to-formdata: 4.5.1 payload: 3.25.0(graphql@16.10.0)(typescript@5.7.3) qs-esm: 7.0.2 - react: 19.0.0 - react-datepicker: 7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-dom: 19.0.0(react@19.0.0) - react-image-crop: 10.1.8(react@19.0.0) - react-select: 5.9.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.2 + react-datepicker: 7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-dom: 19.2.2(react@19.2.2) + react-image-crop: 10.1.8(react@19.2.2) + react-select: 5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) scheduler: 0.25.0 - sonner: 1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + sonner: 1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2) ts-essentials: 10.0.3(typescript@5.7.3) - use-context-selector: 2.0.0(react@19.0.0)(scheduler@0.25.0) + use-context-selector: 2.0.0(react@19.2.2)(scheduler@0.25.0) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -5762,244 +5768,244 @@ snapshots: '@radix-ui/primitive@1.1.1': {} - '@radix-ui/react-arrow@1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-arrow@1.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-checkbox@1.1.4(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-checkbox@1.1.4(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-previous': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-size': 1.1.0(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-previous': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-size': 1.1.0(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-collection@1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-collection@1.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-slot': 1.1.2(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-compose-refs@1.1.1(@types/react@19.2.1)(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-context@1.1.1(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-context@1.1.1(@types/react@19.2.1)(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-direction@1.1.0(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-direction@1.1.0(@types/react@19.2.1)(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-dismissable-layer@1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-focus-guards@1.1.1(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-focus-guards@1.1.1(@types/react@19.2.1)(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-focus-scope@1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-focus-scope@1.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-id@1.1.0(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-id@1.1.0(@types/react@19.2.1)(react@19.2.2)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-label@2.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-label@2.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 - - '@radix-ui/react-popper@1.2.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': - dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-arrow': 1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-rect': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-size': 1.1.0(@types/react@19.0.1)(react@19.0.0) + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) + + '@radix-ui/react-popper@1.2.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@floating-ui/react-dom': 2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-arrow': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-rect': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-size': 1.1.0(@types/react@19.2.1)(react@19.2.2) '@radix-ui/rect': 1.1.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-portal@1.1.4(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-portal@1.1.4(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-presence@1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-presence@1.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-primitive@2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@radix-ui/react-slot': 1.1.2(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-select@2.1.6(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-select@2.1.6(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@radix-ui/number': 1.1.0 '@radix-ui/primitive': 1.1.1 - '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-context': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-direction': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-id': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-popper': 1.2.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@radix-ui/react-slot': 1.1.2(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-use-previous': 1.1.0(@types/react@19.0.1)(react@19.0.0) - '@radix-ui/react-visually-hidden': 1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@radix-ui/react-collection': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-context': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-direction': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-dismissable-layer': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-focus-guards': 1.1.1(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-focus-scope': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-id': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-popper': 1.2.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-portal': 1.1.4(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@radix-ui/react-slot': 1.1.2(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-use-previous': 1.1.0(@types/react@19.2.1)(react@19.2.2) + '@radix-ui/react-visually-hidden': 1.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) aria-hidden: 1.2.4 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-remove-scroll: 2.6.3(@types/react@19.0.1)(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-remove-scroll: 2.6.3(@types/react@19.2.1)(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-slot@1.1.2(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-slot@1.1.2(@types/react@19.2.1)(react@19.2.2)': dependencies: - '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.2.1)(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.2.1)(react@19.2.2)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.2.1)(react@19.2.2)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.2.1)(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-use-previous@1.1.0(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-use-previous@1.1.0(@types/react@19.2.1)(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-use-rect@1.1.0(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-use-rect@1.1.0(@types/react@19.2.1)(react@19.2.2)': dependencies: '@radix-ui/rect': 1.1.0 - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-use-size@1.1.0(@types/react@19.0.1)(react@19.0.0)': + '@radix-ui/react-use-size@1.1.0(@types/react@19.2.1)(react@19.2.2)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.1)(react@19.0.0) - react: 19.0.0 + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.2.1)(react@19.2.2) + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@radix-ui/react-visually-hidden@1.1.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@radix-ui/react-visually-hidden@1.1.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.1)(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 - '@types/react-dom': 19.0.1 + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) '@radix-ui/rect@1.1.0': {} @@ -6401,15 +6407,15 @@ snapshots: '@types/prismjs@1.26.5': {} - '@types/react-dom@19.0.1': + '@types/react-dom@19.2.1(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@types/react-transition-group@4.4.12(@types/react@19.0.1)': + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@types/react@19.0.1': + '@types/react@19.2.1': dependencies: csstype: 3.1.3 @@ -7185,7 +7191,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0(jiti@1.21.7))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0)(eslint@9.21.0(jiti@1.21.7)))(eslint@9.21.0(jiti@1.21.7)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0(jiti@1.21.7))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3)(eslint@9.21.0(jiti@1.21.7)): dependencies: debug: 3.2.7 optionalDependencies: @@ -7207,7 +7213,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.21.0(jiti@1.21.7) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0(jiti@1.21.7))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0)(eslint@9.21.0(jiti@1.21.7)))(eslint@9.21.0(jiti@1.21.7)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.25.0(eslint@9.21.0(jiti@1.21.7))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3)(eslint@9.21.0(jiti@1.21.7)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -7458,9 +7464,9 @@ snapshots: functions-have-names@1.2.3: {} - geist@1.3.1(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4)): + geist@1.3.1(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4)): dependencies: - next: 15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) get-caller-file@2.0.5: {} @@ -7925,9 +7931,9 @@ snapshots: lru-cache@10.4.3: {} - lucide-react@0.378.0(react@19.0.0): + lucide-react@0.378.0(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 math-intrinsics@1.1.0: {} @@ -8253,23 +8259,23 @@ snapshots: negotiator@1.0.0: {} - next-intl@3.26.5(next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(react@19.0.0): + next-intl@3.26.5(next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(react@19.2.2): dependencies: '@formatjs/intl-localematcher': 0.5.10 negotiator: 1.0.0 - next: 15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) - react: 19.0.0 - use-intl: 3.26.5(react@19.0.0) + next: 15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + react: 19.2.2 + use-intl: 3.26.5(react@19.2.2) - next@15.5.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): + next@15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): dependencies: '@next/env': 15.5.4 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001701 postcss: 8.4.31 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + styled-jsx: 5.1.6(react@19.2.2) optionalDependencies: '@next/swc-darwin-arm64': 15.5.4 '@next/swc-darwin-x64': 15.5.4 @@ -8578,11 +8584,11 @@ snapshots: prettier@3.5.3: {} - prism-react-renderer@2.4.1(react@19.0.0): + prism-react-renderer@2.4.1(react@19.2.2): dependencies: '@types/prismjs': 1.26.5 clsx: 2.1.1 - react: 19.0.0 + react: 19.2.2 prismjs@1.29.0: {} @@ -8625,106 +8631,106 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-datepicker@7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-datepicker@7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - '@floating-ui/react': 0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react': 0.27.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) clsx: 2.1.1 date-fns: 3.6.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react-diff-viewer-continued@4.0.4(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-diff-viewer-continued@4.0.4(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@emotion/css': 11.13.5 - '@emotion/react': 11.14.0(@types/react@19.0.1)(react@19.0.0) + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.2) classnames: 2.5.1 diff: 5.2.0 memoize-one: 6.0.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) transitivePeerDependencies: - '@types/react' - supports-color - react-dom@19.0.0(react@19.0.0): + react-dom@19.2.2(react@19.2.2): dependencies: - react: 19.0.0 - scheduler: 0.25.0 + react: 19.2.2 + scheduler: 0.27.0 - react-error-boundary@3.1.4(react@19.0.0): + react-error-boundary@3.1.4(react@19.2.2): dependencies: '@babel/runtime': 7.26.9 - react: 19.0.0 + react: 19.2.2 - react-error-boundary@4.1.2(react@19.0.0): + react-error-boundary@4.1.2(react@19.2.2): dependencies: '@babel/runtime': 7.26.9 - react: 19.0.0 + react: 19.2.2 - react-hook-form@7.45.4(react@19.0.0): + react-hook-form@7.45.4(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 - react-image-crop@10.1.8(react@19.0.0): + react-image-crop@10.1.8(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 react-is@16.13.1: {} - react-remove-scroll-bar@2.3.8(@types/react@19.0.1)(react@19.0.0): + react-remove-scroll-bar@2.3.8(@types/react@19.2.1)(react@19.2.2): dependencies: - react: 19.0.0 - react-style-singleton: 2.2.3(@types/react@19.0.1)(react@19.0.0) + react: 19.2.2 + react-style-singleton: 2.2.3(@types/react@19.2.1)(react@19.2.2) tslib: 2.8.1 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - react-remove-scroll@2.6.3(@types/react@19.0.1)(react@19.0.0): + react-remove-scroll@2.6.3(@types/react@19.2.1)(react@19.2.2): dependencies: - react: 19.0.0 - react-remove-scroll-bar: 2.3.8(@types/react@19.0.1)(react@19.0.0) - react-style-singleton: 2.2.3(@types/react@19.0.1)(react@19.0.0) + react: 19.2.2 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.1)(react@19.2.2) + react-style-singleton: 2.2.3(@types/react@19.2.1)(react@19.2.2) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.0.1)(react@19.0.0) - use-sidecar: 1.1.3(@types/react@19.0.1)(react@19.0.0) + use-callback-ref: 1.3.3(@types/react@19.2.1)(react@19.2.2) + use-sidecar: 1.1.3(@types/react@19.2.1)(react@19.2.2) optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - react-select@5.9.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-select@5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.26.9 '@emotion/cache': 11.14.0 - '@emotion/react': 11.14.0(@types/react@19.0.1)(react@19.0.0) + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.2) '@floating-ui/dom': 1.6.13 - '@types/react-transition-group': 4.4.12(@types/react@19.0.1) + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - use-isomorphic-layout-effect: 1.2.0(@types/react@19.0.1)(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + use-isomorphic-layout-effect: 1.2.0(@types/react@19.2.1)(react@19.2.2) transitivePeerDependencies: - '@types/react' - supports-color - react-style-singleton@2.2.3(@types/react@19.0.1)(react@19.0.0): + react-style-singleton@2.2.3(@types/react@19.2.1)(react@19.2.2): dependencies: get-nonce: 1.0.1 - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-transition-group@4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.26.9 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react@19.0.0: {} + react@19.2.2: {} read-cache@1.0.0: dependencies: @@ -8844,6 +8850,8 @@ snapshots: scheduler@0.25.0: {} + scheduler@0.27.0: {} + scmp@2.1.0: {} secure-json-parse@2.7.0: {} @@ -8978,10 +8986,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + sonner@1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) source-map-js@1.2.1: {} @@ -9109,10 +9117,10 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.4.2 - styled-jsx@5.1.6(react@19.0.0): + styled-jsx@5.1.6(react@19.2.2): dependencies: client-only: 0.0.1 - react: 19.0.0 + react: 19.2.2 stylis@4.2.0: {} @@ -9364,37 +9372,37 @@ snapshots: dependencies: punycode: 2.3.1 - use-callback-ref@1.3.3(@types/react@19.0.1)(react@19.0.0): + use-callback-ref@1.3.3(@types/react@19.2.1)(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - use-context-selector@2.0.0(react@19.0.0)(scheduler@0.25.0): + use-context-selector@2.0.0(react@19.2.2)(scheduler@0.25.0): dependencies: - react: 19.0.0 + react: 19.2.2 scheduler: 0.25.0 - use-intl@3.26.5(react@19.0.0): + use-intl@3.26.5(react@19.2.2): dependencies: '@formatjs/fast-memoize': 2.2.6 intl-messageformat: 10.7.15 - react: 19.0.0 + react: 19.2.2 - use-isomorphic-layout-effect@1.2.0(@types/react@19.0.1)(react@19.0.0): + use-isomorphic-layout-effect@1.2.0(@types/react@19.2.1)(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - use-sidecar@1.1.3(@types/react@19.0.1)(react@19.0.0): + use-sidecar@1.1.3(@types/react@19.2.1)(react@19.2.2): dependencies: detect-node-es: 1.1.0 - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 utf8-byte-length@1.0.5: {} diff --git a/examples/multi-tenant/package.json b/examples/multi-tenant/package.json index cdb2bcaaa41..5670616d4e4 100644 --- a/examples/multi-tenant/package.json +++ b/examples/multi-tenant/package.json @@ -25,7 +25,7 @@ "cross-env": "^7.0.3", "dotenv": "^8.2.0", "graphql": "^16.9.0", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "latest", "qs-esm": "7.0.2", "react": "^19.2.1", diff --git a/examples/multi-tenant/pnpm-lock.yaml b/examples/multi-tenant/pnpm-lock.yaml index cef3ad6e16a..0eaed6b540b 100644 --- a/examples/multi-tenant/pnpm-lock.yaml +++ b/examples/multi-tenant/pnpm-lock.yaml @@ -13,19 +13,19 @@ importers: version: 3.28.0(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2)) '@payloadcms/db-postgres': specifier: ^3.25.0 - version: 3.28.0(@types/react@19.0.1)(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react@19.0.0) + version: 3.28.0(@types/react@19.2.1)(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react@19.2.2) '@payloadcms/next': specifier: latest - version: 3.28.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.28.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@payloadcms/plugin-multi-tenant': specifier: latest - version: 3.28.0(@payloadcms/ui@3.28.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2)) + version: 3.28.0(@payloadcms/ui@3.28.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2)) '@payloadcms/richtext-lexical': specifier: latest - version: 3.28.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.28.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)(yjs@13.6.24) + version: 3.28.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.28.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)(yjs@13.6.24) '@payloadcms/ui': specifier: latest - version: 3.28.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + version: 3.28.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -36,8 +36,8 @@ importers: specifier: ^16.9.0 version: 16.10.0 next: - specifier: ^15.0.0 - version: 15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + specifier: ^15.4.9 + version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest version: 3.28.0(graphql@16.10.0)(typescript@5.5.2) @@ -45,11 +45,11 @@ importers: specifier: 7.0.2 version: 7.0.2 react: - specifier: 19.0.0 - version: 19.0.0 + specifier: ^19.2.1 + version: 19.2.2 react-dom: - specifier: 19.0.0 - version: 19.0.0(react@19.0.0) + specifier: ^19.2.1 + version: 19.2.2(react@19.2.2) sharp: specifier: 0.32.6 version: 0.32.6 @@ -61,11 +61,11 @@ importers: specifier: ^1.6.13 version: 1.11.9(@swc/helpers@0.5.15) '@types/react': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1 '@types/react-dom': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -137,8 +137,8 @@ packages: '@dnd-kit/core@6.0.8': resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} peerDependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@dnd-kit/sortable@7.0.2': resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} @@ -154,8 +154,8 @@ packages: '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} - '@emnapi/runtime@1.3.1': - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -843,107 +843,139 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -1050,8 +1082,8 @@ packages: resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} peerDependencies: monaco-editor: '>= 0.25.0 < 1' - react: 19.0.0 - react-dom: 19.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@mongodb-js/saslprep@1.2.0': resolution: {integrity: sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==} @@ -1059,53 +1091,56 @@ packages: '@next/env@15.2.2': resolution: {integrity: sha512-yWgopCfA9XDR8ZH3taB5nRKtKJ1Q5fYsTOuYkzIIoS8TJ0UAUKAGF73JnGszbjk2ufAQDj6mDdgsJAFx5CLtYQ==} + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + '@next/eslint-plugin-next@15.2.2': resolution: {integrity: sha512-1+BzokFuFQIfLaRxUKf2u5In4xhPV7tUgKcK53ywvFl6+LXHWHpFkcV7VNeKlyQKUotwiq4fy/aDNF9EiUp4RQ==} - '@next/swc-darwin-arm64@15.2.2': - resolution: {integrity: sha512-HNBRnz+bkZ+KfyOExpUxTMR0Ow8nkkcE6IlsdEa9W/rI7gefud19+Sn1xYKwB9pdCdxIP1lPru/ZfjfA+iT8pw==} + '@next/swc-darwin-arm64@15.5.7': + resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.2.2': - resolution: {integrity: sha512-mJOUwp7al63tDpLpEFpKwwg5jwvtL1lhRW2fI1Aog0nYCPAhxbJsaZKdoVyPZCy8MYf/iQVNDuk/+i29iLCzIA==} + '@next/swc-darwin-x64@15.5.7': + resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.2.2': - resolution: {integrity: sha512-5ZZ0Zwy3SgMr7MfWtRE7cQWVssfOvxYfD9O7XHM7KM4nrf5EOeqwq67ZXDgo86LVmffgsu5tPO57EeFKRnrfSQ==} + '@next/swc-linux-arm64-gnu@15.5.7': + resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.2.2': - resolution: {integrity: sha512-cgKWBuFMLlJ4TWcFHl1KOaVVUAF8vy4qEvX5KsNd0Yj5mhu989QFCq1WjuaEbv/tO1ZpsQI6h/0YR8bLwEi+nA==} + '@next/swc-linux-arm64-musl@15.5.7': + resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.2.2': - resolution: {integrity: sha512-c3kWSOSsVL8rcNBBfOq1+/j2PKs2nsMwJUV4icUxRgGBwUOfppeh7YhN5s79enBQFU+8xRgVatFkhHU1QW7yUA==} + '@next/swc-linux-x64-gnu@15.5.7': + resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.2.2': - resolution: {integrity: sha512-PXTW9PLTxdNlVYgPJ0equojcq1kNu5NtwcNjRjHAB+/sdoKZ+X8FBu70fdJFadkxFIGekQTyRvPMFF+SOJaQjw==} + '@next/swc-linux-x64-musl@15.5.7': + resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.2.2': - resolution: {integrity: sha512-nG644Es5llSGEcTaXhnGWR/aThM/hIaz0jx4MDg4gWC8GfTCp8eDBWZ77CVuv2ha/uL9Ce+nPTfYkSLG67/sHg==} + '@next/swc-win32-arm64-msvc@15.5.7': + resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.2.2': - resolution: {integrity: sha512-52nWy65S/R6/kejz3jpvHAjZDPKIbEQu4x9jDBzmB9jJfuOy5rspjKu4u77+fI4M/WzLXrrQd57hlFGzz1ubcQ==} + '@next/swc-win32-x64-msvc@15.5.7': + resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1315,16 +1350,18 @@ packages: '@types/pg@8.10.2': resolution: {integrity: sha512-MKFs9P6nJ+LAeHLU3V0cODEOgyThJ3OAnmOlsZsxux6sfQs3HRXR5bBn7xG5DjckEFhTAxsXi7k7cd0pCMxpJw==} - '@types/react-dom@19.0.1': - resolution: {integrity: sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 '@types/react-transition-group@4.4.12': resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} peerDependencies: '@types/react': '*' - '@types/react@19.0.1': - resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1760,6 +1797,10 @@ packages: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -2757,13 +2798,13 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.2.2: - resolution: {integrity: sha512-dgp8Kcx5XZRjMw2KNwBtUzhngRaURPioxoNIVl5BOyJbhi9CUgEtKDO7fx5wh8Z8vOVX1nYZ9meawJoRrlASYA==} + next@15.5.8: + resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 + '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 @@ -3076,10 +3117,10 @@ packages: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom@19.0.0: - resolution: {integrity: sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==} + react-dom@19.2.2: + resolution: {integrity: sha512-fhyD2BLrew6qYf4NNtHff1rLXvzR25rq49p+FeqByOazc6TcSi2n8EYulo5C1PbH+1uBW++5S1SG7FcUU6mlDg==} peerDependencies: - react: ^19.0.0 + react: ^19.2.2 react-error-boundary@3.1.4: resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} @@ -3112,8 +3153,8 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' - react@19.0.0: - resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} + react@19.2.2: + resolution: {integrity: sha512-BdOGOY8OKRBcgoDkwqA8Q5XvOIhoNx/Sh6BnGJlet2Abt0X5BK0BDrqGyQgLhAVjD2nAg5f6o01u/OPUhG022Q==} engines: {node: '>=0.10.0'} readable-stream@3.6.2: @@ -3201,6 +3242,9 @@ packages: scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + scmp@2.1.0: resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} @@ -3216,6 +3260,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3232,8 +3281,8 @@ packages: resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} engines: {node: '>=14.15.0'} - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -3713,34 +3762,34 @@ snapshots: '@date-fns/tz@1.2.0': {} - '@dnd-kit/accessibility@3.1.1(react@19.0.0)': + '@dnd-kit/accessibility@3.1.1(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + '@dnd-kit/accessibility': 3.1.1(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tslib: 2.8.1 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/utilities': 3.2.2(react@19.0.0) - react: 19.0.0 + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.0.0)': + '@dnd-kit/utilities@3.2.2(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 tslib: 2.8.1 '@drizzle-team/brocli@0.10.2': {} - '@emnapi/runtime@1.3.1': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -3783,19 +3832,19 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.0.1)(react@19.0.0)': + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.2)': dependencies: '@babel/runtime': 7.26.10 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.0.0) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.2) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 transitivePeerDependencies: - supports-color @@ -3811,9 +3860,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.0.0)': + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.2)': dependencies: - react: 19.0.0 + react: 19.2.2 '@emotion/utils@1.4.2': {} @@ -4134,23 +4183,23 @@ snapshots: '@eslint/js@8.57.1': {} - '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: body-scroll-lock: 4.0.0-beta.0 focus-trap: 7.5.4 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) - '@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@faceless-ui/window-info@3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@faceless-ui/window-info@3.0.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@floating-ui/core@1.6.9': dependencies: @@ -4161,18 +4210,18 @@ snapshots: '@floating-ui/core': 1.6.9 '@floating-ui/utils': 0.2.9 - '@floating-ui/react-dom@2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react-dom@2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@floating-ui/dom': 1.6.13 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@floating-ui/react@0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@floating-ui/react@0.27.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react-dom': 2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@floating-ui/utils': 0.2.9 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tabbable: 6.2.0 '@floating-ui/utils@0.2.9': {} @@ -4189,79 +4238,101 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@img/sharp-darwin-arm64@0.33.5': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - '@img/sharp-libvips-darwin-arm64@1.0.4': + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.0.4': + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.0.4': + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.0.5': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.0.4': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-arm64@0.33.5': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-arm@0.33.5': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linuxmusl-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true - '@img/sharp-wasm32@0.33.5': + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.3.1 + '@emnapi/runtime': 1.7.1 optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': optional: true '@jridgewell/gen-mapping@0.3.8': @@ -4297,7 +4368,7 @@ snapshots: lexical: 0.27.1 prismjs: 1.30.0 - '@lexical/devtools-core@0.27.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@lexical/devtools-core@0.27.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@lexical/html': 0.27.1 '@lexical/link': 0.27.1 @@ -4305,8 +4376,8 @@ snapshots: '@lexical/table': 0.27.1 '@lexical/utils': 0.27.1 lexical: 0.27.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@lexical/dragon@0.27.1': dependencies: @@ -4372,11 +4443,11 @@ snapshots: '@lexical/utils': 0.27.1 lexical: 0.27.1 - '@lexical/react@0.27.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(yjs@13.6.24)': + '@lexical/react@0.27.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.24)': dependencies: '@lexical/clipboard': 0.27.1 '@lexical/code': 0.27.1 - '@lexical/devtools-core': 0.27.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@lexical/devtools-core': 0.27.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@lexical/dragon': 0.27.1 '@lexical/hashtag': 0.27.1 '@lexical/history': 0.27.1 @@ -4393,9 +4464,9 @@ snapshots: '@lexical/utils': 0.27.1 '@lexical/yjs': 0.27.1(yjs@13.6.24) lexical: 0.27.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-error-boundary: 3.1.4(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 3.1.4(react@19.2.2) transitivePeerDependencies: - yjs @@ -4438,12 +4509,12 @@ snapshots: dependencies: state-local: 1.0.7 - '@monaco-editor/react@4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + '@monaco-editor/react@4.7.0(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@monaco-editor/loader': 1.5.0 monaco-editor: 0.52.2 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@mongodb-js/saslprep@1.2.0': dependencies: @@ -4451,32 +4522,34 @@ snapshots: '@next/env@15.2.2': {} + '@next/env@15.5.8': {} + '@next/eslint-plugin-next@15.2.2': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.2.2': + '@next/swc-darwin-arm64@15.5.7': optional: true - '@next/swc-darwin-x64@15.2.2': + '@next/swc-darwin-x64@15.5.7': optional: true - '@next/swc-linux-arm64-gnu@15.2.2': + '@next/swc-linux-arm64-gnu@15.5.7': optional: true - '@next/swc-linux-arm64-musl@15.2.2': + '@next/swc-linux-arm64-musl@15.5.7': optional: true - '@next/swc-linux-x64-gnu@15.2.2': + '@next/swc-linux-x64-gnu@15.5.7': optional: true - '@next/swc-linux-x64-musl@15.2.2': + '@next/swc-linux-x64-musl@15.5.7': optional: true - '@next/swc-win32-arm64-msvc@15.2.2': + '@next/swc-win32-arm64-msvc@15.5.7': optional: true - '@next/swc-win32-x64-msvc@15.2.2': + '@next/swc-win32-x64-msvc@15.5.7': optional: true '@nodelib/fs.scandir@2.1.5': @@ -4510,13 +4583,13 @@ snapshots: - socks - supports-color - '@payloadcms/db-postgres@3.28.0(@types/react@19.0.1)(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react@19.0.0)': + '@payloadcms/db-postgres@3.28.0(@types/react@19.2.1)(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react@19.2.2)': dependencies: - '@payloadcms/drizzle': 3.28.0(@types/pg@8.10.2)(@types/react@19.0.1)(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(pg@8.11.3)(react@19.0.0) + '@payloadcms/drizzle': 3.28.0(@types/pg@8.10.2)(@types/react@19.2.1)(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(pg@8.11.3)(react@19.2.2) '@types/pg': 8.10.2 console-table-printer: 2.12.1 drizzle-kit: 0.28.0 - drizzle-orm: 0.36.1(@types/pg@8.10.2)(@types/react@19.0.1)(pg@8.11.3)(react@19.0.0) + drizzle-orm: 0.36.1(@types/pg@8.10.2)(@types/react@19.2.1)(pg@8.11.3)(react@19.2.2) payload: 3.28.0(graphql@16.10.0)(typescript@5.5.2) pg: 8.11.3 prompts: 2.4.2 @@ -4553,10 +4626,10 @@ snapshots: - sqlite3 - supports-color - '@payloadcms/drizzle@3.28.0(@types/pg@8.10.2)(@types/react@19.0.1)(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(pg@8.11.3)(react@19.0.0)': + '@payloadcms/drizzle@3.28.0(@types/pg@8.10.2)(@types/react@19.2.1)(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(pg@8.11.3)(react@19.2.2)': dependencies: console-table-printer: 2.12.1 - drizzle-orm: 0.36.1(@types/pg@8.10.2)(@types/react@19.0.1)(pg@8.11.3)(react@19.0.0) + drizzle-orm: 0.36.1(@types/pg@8.10.2)(@types/react@19.2.1)(pg@8.11.3)(react@19.2.2) payload: 3.28.0(graphql@16.10.0)(typescript@5.5.2) prompts: 2.4.2 to-snake-case: 1.0.0 @@ -4603,12 +4676,12 @@ snapshots: transitivePeerDependencies: - typescript - '@payloadcms/next@3.28.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/next@3.28.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/graphql': 3.28.0(graphql@16.10.0)(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(typescript@5.5.2) '@payloadcms/translations': 3.28.0 - '@payloadcms/ui': 3.28.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/ui': 3.28.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) busboy: 1.6.0 dequal: 2.0.3 file-type: 19.3.0 @@ -4616,11 +4689,11 @@ snapshots: graphql-http: 1.22.4(graphql@16.10.0) graphql-playground-html: 1.6.30 http-status: 2.1.0 - next: 15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) path-to-regexp: 6.3.0 payload: 3.28.0(graphql@16.10.0)(typescript@5.5.2) qs-esm: 7.0.2 - react-diff-viewer-continued: 4.0.5(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react-diff-viewer-continued: 4.0.5(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) sass: 1.77.4 uuid: 10.0.0 transitivePeerDependencies: @@ -4631,29 +4704,29 @@ snapshots: - supports-color - typescript - '@payloadcms/plugin-multi-tenant@3.28.0(@payloadcms/ui@3.28.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))': + '@payloadcms/plugin-multi-tenant@3.28.0(@payloadcms/ui@3.28.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))': dependencies: - '@payloadcms/ui': 3.28.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) - next: 15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + '@payloadcms/ui': 3.28.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: 3.28.0(graphql@16.10.0)(typescript@5.5.2) - '@payloadcms/richtext-lexical@3.28.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.28.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2))(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)(yjs@13.6.24)': + '@payloadcms/richtext-lexical@3.28.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.28.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)(yjs@13.6.24)': dependencies: - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/scroll-info': 2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@lexical/headless': 0.27.1 '@lexical/html': 0.27.1 '@lexical/link': 0.27.1 '@lexical/list': 0.27.1 '@lexical/mark': 0.27.1 - '@lexical/react': 0.27.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(yjs@13.6.24) + '@lexical/react': 0.27.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.24) '@lexical/rich-text': 0.27.1 '@lexical/selection': 0.27.1 '@lexical/table': 0.27.1 '@lexical/utils': 0.27.1 - '@payloadcms/next': 3.28.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/next': 3.28.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@payloadcms/translations': 3.28.0 - '@payloadcms/ui': 3.28.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2) + '@payloadcms/ui': 3.28.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -4666,9 +4739,9 @@ snapshots: micromark-extension-mdx-jsx: 3.0.1 payload: 3.28.0(graphql@16.10.0)(typescript@5.5.2) qs-esm: 7.0.2 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-error-boundary: 4.1.2(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 4.1.2(react@19.2.2) ts-essentials: 10.0.3(typescript@5.5.2) uuid: 10.0.0 transitivePeerDependencies: @@ -4683,33 +4756,33 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.28.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.5.2)': + '@payloadcms/ui@3.28.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.28.0(graphql@16.10.0)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: '@date-fns/tz': 1.2.0 - '@dnd-kit/core': 6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0) - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/scroll-info': 2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@faceless-ui/window-info': 3.0.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - '@monaco-editor/react': 4.7.0(monaco-editor@0.52.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/window-info': 3.0.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@monaco-editor/react': 4.7.0(monaco-editor@0.52.2)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/translations': 3.28.0 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) object-to-formdata: 4.5.1 payload: 3.28.0(graphql@16.10.0)(typescript@5.5.2) qs-esm: 7.0.2 - react: 19.0.0 - react-datepicker: 7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - react-dom: 19.0.0(react@19.0.0) - react-image-crop: 10.1.8(react@19.0.0) - react-select: 5.9.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + react: 19.2.2 + react-datepicker: 7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-dom: 19.2.2(react@19.2.2) + react-image-crop: 10.1.8(react@19.2.2) + react-select: 5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) scheduler: 0.25.0 - sonner: 1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + sonner: 1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2) ts-essentials: 10.0.3(typescript@5.5.2) - use-context-selector: 2.0.0(react@19.0.0)(scheduler@0.25.0) + use-context-selector: 2.0.0(react@19.2.2)(scheduler@0.25.0) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -4826,15 +4899,15 @@ snapshots: pg-protocol: 1.8.0 pg-types: 4.0.2 - '@types/react-dom@19.0.1': + '@types/react-dom@19.2.1(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@types/react-transition-group@4.4.12(@types/react@19.0.1)': + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@types/react@19.0.1': + '@types/react@19.2.1': dependencies: csstype: 3.1.3 @@ -5303,6 +5376,9 @@ snapshots: detect-libc@2.0.3: {} + detect-libc@2.1.2: + optional: true + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -5333,12 +5409,12 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.36.1(@types/pg@8.10.2)(@types/react@19.0.1)(pg@8.11.3)(react@19.0.0): + drizzle-orm@0.36.1(@types/pg@8.10.2)(@types/react@19.2.1)(pg@8.11.3)(react@19.2.2): optionalDependencies: '@types/pg': 8.10.2 - '@types/react': 19.0.1 + '@types/react': 19.2.1 pg: 8.11.3 - react: 19.0.0 + react: 19.2.2 dunder-proto@1.0.1: dependencies: @@ -5619,7 +5695,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.26.1(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.26.1(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -5641,7 +5717,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.26.1(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.26.1(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.5)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -6568,28 +6644,26 @@ snapshots: natural-compare@1.4.0: {} - next@15.2.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4): + next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): dependencies: - '@next/env': 15.2.2 - '@swc/counter': 0.1.3 + '@next/env': 15.5.8 '@swc/helpers': 0.5.15 - busboy: 1.6.0 caniuse-lite: 1.0.30001703 postcss: 8.4.31 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - styled-jsx: 5.1.6(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + styled-jsx: 5.1.6(react@19.2.2) optionalDependencies: - '@next/swc-darwin-arm64': 15.2.2 - '@next/swc-darwin-x64': 15.2.2 - '@next/swc-linux-arm64-gnu': 15.2.2 - '@next/swc-linux-arm64-musl': 15.2.2 - '@next/swc-linux-x64-gnu': 15.2.2 - '@next/swc-linux-x64-musl': 15.2.2 - '@next/swc-win32-arm64-msvc': 15.2.2 - '@next/swc-win32-x64-msvc': 15.2.2 + '@next/swc-darwin-arm64': 15.5.7 + '@next/swc-darwin-x64': 15.5.7 + '@next/swc-linux-arm64-gnu': 15.5.7 + '@next/swc-linux-arm64-musl': 15.5.7 + '@next/swc-linux-x64-gnu': 15.5.7 + '@next/swc-linux-x64-musl': 15.5.7 + '@next/swc-win32-arm64-msvc': 15.5.7 + '@next/swc-win32-x64-msvc': 15.5.7 sass: 1.77.4 - sharp: 0.33.5 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -6931,75 +7005,75 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-datepicker@7.6.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-datepicker@7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - '@floating-ui/react': 0.27.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@floating-ui/react': 0.27.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) clsx: 2.1.1 date-fns: 3.6.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react-diff-viewer-continued@4.0.5(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-diff-viewer-continued@4.0.5(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@emotion/css': 11.13.5 - '@emotion/react': 11.14.0(@types/react@19.0.1)(react@19.0.0) + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.2) classnames: 2.5.1 diff: 5.2.0 memoize-one: 6.0.0 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) transitivePeerDependencies: - '@types/react' - supports-color - react-dom@19.0.0(react@19.0.0): + react-dom@19.2.2(react@19.2.2): dependencies: - react: 19.0.0 - scheduler: 0.25.0 + react: 19.2.2 + scheduler: 0.27.0 - react-error-boundary@3.1.4(react@19.0.0): + react-error-boundary@3.1.4(react@19.2.2): dependencies: '@babel/runtime': 7.26.10 - react: 19.0.0 + react: 19.2.2 - react-error-boundary@4.1.2(react@19.0.0): + react-error-boundary@4.1.2(react@19.2.2): dependencies: '@babel/runtime': 7.26.10 - react: 19.0.0 + react: 19.2.2 - react-image-crop@10.1.8(react@19.0.0): + react-image-crop@10.1.8(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 react-is@16.13.1: {} - react-select@5.9.0(@types/react@19.0.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-select@5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.26.10 '@emotion/cache': 11.14.0 - '@emotion/react': 11.14.0(@types/react@19.0.1)(react@19.0.0) + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.2) '@floating-ui/dom': 1.6.13 - '@types/react-transition-group': 4.4.12(@types/react@19.0.1) + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - use-isomorphic-layout-effect: 1.2.0(@types/react@19.0.1)(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + use-isomorphic-layout-effect: 1.2.0(@types/react@19.2.1)(react@19.2.2) transitivePeerDependencies: - '@types/react' - supports-color - react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + react-transition-group@4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.26.10 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react@19.0.0: {} + react@19.2.2: {} readable-stream@3.6.2: dependencies: @@ -7098,6 +7172,8 @@ snapshots: scheduler@0.25.0: {} + scheduler@0.27.0: {} + scmp@2.1.0: {} secure-json-parse@2.7.0: {} @@ -7106,6 +7182,9 @@ snapshots: semver@7.7.1: {} + semver@7.7.3: + optional: true + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -7141,31 +7220,36 @@ snapshots: transitivePeerDependencies: - bare-buffer - sharp@0.33.5: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.3 - semver: 7.7.1 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -7224,10 +7308,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@1.7.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + sonner@1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) source-map-js@1.2.1: {} @@ -7333,10 +7417,10 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.4.2 - styled-jsx@5.1.6(react@19.0.0): + styled-jsx@5.1.6(react@19.2.2): dependencies: client-only: 0.0.1 - react: 19.0.0 + react: 19.2.2 stylis@4.2.0: {} @@ -7537,16 +7621,16 @@ snapshots: dependencies: punycode: 2.3.1 - use-context-selector@2.0.0(react@19.0.0)(scheduler@0.25.0): + use-context-selector@2.0.0(react@19.2.2)(scheduler@0.25.0): dependencies: - react: 19.0.0 + react: 19.2.2 scheduler: 0.25.0 - use-isomorphic-layout-effect@1.2.0(@types/react@19.0.1)(react@19.0.0): + use-isomorphic-layout-effect@1.2.0(@types/react@19.2.1)(react@19.2.2): dependencies: - react: 19.0.0 + react: 19.2.2 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 utf8-byte-length@1.0.5: {} diff --git a/examples/remix/payload/package.json b/examples/remix/payload/package.json index 5aa7f21340c..d9cb846f59a 100644 --- a/examples/remix/payload/package.json +++ b/examples/remix/payload/package.json @@ -27,7 +27,7 @@ "@payloadcms/richtext-lexical": "latest", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1", diff --git a/examples/remix/payload/pnpm-lock.yaml b/examples/remix/payload/pnpm-lock.yaml new file mode 100644 index 00000000000..026a809729b --- /dev/null +++ b/examples/remix/payload/pnpm-lock.yaml @@ -0,0 +1,6610 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@payloadcms/db-mongodb': + specifier: latest + version: 3.68.2(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3)) + '@payloadcms/next': + specifier: latest + version: 3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) + '@payloadcms/richtext-lexical': + specifier: latest + version: 3.68.2(@faceless-ui/modal@3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3))(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)(yjs@13.6.27) + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + graphql: + specifier: ^16.8.1 + version: 16.12.0 + next: + specifier: ^15.4.9 + version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + payload: + specifier: latest + version: 3.68.2(graphql@16.12.0)(typescript@5.7.3) + react: + specifier: ^19.2.1 + version: 19.2.2 + react-dom: + specifier: ^19.2.1 + version: 19.2.2(react@19.2.2) + sharp: + specifier: 0.32.6 + version: 0.32.6 + devDependencies: + '@eslint/eslintrc': + specifier: ^3.2.0 + version: 3.3.3 + '@types/node': + specifier: ^22.5.4 + version: 22.19.2 + '@types/react': + specifier: 19.2.1 + version: 19.2.1 + '@types/react-dom': + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) + eslint: + specifier: ^9.16.0 + version: 9.39.1 + eslint-config-next: + specifier: 15.1.5 + version: 15.1.5(eslint@9.39.1)(typescript@5.7.3) + prettier: + specifier: ^3.4.2 + version: 3.7.4 + typescript: + specifier: 5.7.3 + version: 5.7.3 + +packages: + + '@apidevtools/json-schema-ref-parser@11.9.3': + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} + engines: {node: '>= 16'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@borewit/text-codec@0.1.1': + resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} + + '@date-fns/tz@1.2.0': + resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==} + + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.0.8': + resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/sortable@7.0.2': + resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} + peerDependencies: + '@dnd-kit/core': ^6.0.7 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + peerDependencies: + react: '>=16.8.0' + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.3': + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.1': + resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@faceless-ui/modal@3.0.0': + resolution: {integrity: sha512-o3oEFsot99EQ8RJc1kL3s/nNMHX+y+WMXVzSSmca9L0l2MR6ez2QM1z1yIelJX93jqkLXQ9tW+R9tmsYa+O4Qg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@faceless-ui/scroll-info@2.0.0': + resolution: {integrity: sha512-BkyJ9OQ4bzpKjE3UhI8BhcG36ZgfB4run8TmlaR4oMFUbl59dfyarNfjveyimrxIso9RhFEja/AJ5nQmbcR9hw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@faceless-ui/window-info@3.0.1': + resolution: {integrity: sha512-uPjdJYE/j7hqVNelE9CRUNOeXuXDdPxR4DMe+oz3xwyZi2Y4CxsfpfdPTqqwmNAZa1P33O+ZiCyIkBEeNed0kw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.27.16': + resolution: {integrity: sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==} + peerDependencies: + react: '>=17.0.0' + react-dom: '>=17.0.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@lexical/clipboard@0.35.0': + resolution: {integrity: sha512-ko7xSIIiayvDiqjNDX6fgH9RlcM6r9vrrvJYTcfGVBor5httx16lhIi0QJZ4+RNPvGtTjyFv4bwRmsixRRwImg==} + + '@lexical/code@0.35.0': + resolution: {integrity: sha512-ox4DZwETQ9IA7+DS6PN8RJNwSAF7RMjL7YTVODIqFZ5tUFIf+5xoCHbz7Fll0Bvixlp12hVH90xnLwTLRGpkKw==} + + '@lexical/devtools-core@0.35.0': + resolution: {integrity: sha512-C2wwtsMCR6ZTfO0TqpSM17RLJWyfHmifAfCTjFtOJu15p3M6NO/nHYK5Mt7YMQteuS89mOjB4ng8iwoLEZ6QpQ==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/dragon@0.35.0': + resolution: {integrity: sha512-SL6mT5pcqrt6hEbJ16vWxip5+r3uvMd0bQV5UUxuk+cxIeuP86iTgRh0HFR7SM2dRTYovL6/tM/O+8QLAUGTIg==} + + '@lexical/hashtag@0.35.0': + resolution: {integrity: sha512-LYJWzXuO2ZjKsvQwrLkNZiS2TsjwYkKjlDgtugzejquTBQ/o/nfSn/MmVx6EkYLOYizaJemmZbz3IBh+u732FA==} + + '@lexical/headless@0.35.0': + resolution: {integrity: sha512-UPmCqOsdGGC7/8Fkae2ADkTQfxTZOKxNEVKuqPfCkFs4Bag3s4z3V61jE+wYzqyU8eJh4DqZYSHoPzZCj8P9jg==} + + '@lexical/history@0.35.0': + resolution: {integrity: sha512-onjDRLLxGbCfHexSxxrQaDaieIHyV28zCDrbxR5dxTfW8F8PxjuNyuaG0z6o468AXYECmclxkP+P4aT6poHEpQ==} + + '@lexical/html@0.35.0': + resolution: {integrity: sha512-rXGFE5S5rKsg3tVnr1s4iEgOfCApNXGpIFI3T2jGEShaCZ5HLaBY9NVBXnE9Nb49e9bkDkpZ8FZd1qokCbQXbw==} + + '@lexical/link@0.35.0': + resolution: {integrity: sha512-+0Wx6cBwO8TfdMzpkYFacsmgFh8X1rkiYbq3xoLvk3qV8upYxaMzK1s8Q1cpKmWyI0aZrU6z7fiK4vUqB7+69w==} + + '@lexical/list@0.35.0': + resolution: {integrity: sha512-owsmc8iwgExBX8sFe8fKTiwJVhYULt9hD1RZ/HwfaiEtRZZkINijqReOBnW2mJfRxBzhFSWc4NG3ISB+fHYzqw==} + + '@lexical/mark@0.35.0': + resolution: {integrity: sha512-W0hwMTAVeexvpk9/+J6n1G/sNkpI/Meq1yeDazahFLLAwXLHtvhIAq2P/klgFknDy1hr8X7rcsQuN/bqKcKHYg==} + + '@lexical/markdown@0.35.0': + resolution: {integrity: sha512-BlNyXZAt4gWidMw0SRWrhBETY1BpPglFBZI7yzfqukFqgXRh7HUQA28OYeI/nsx9pgNob8TiUduUwShqqvOdEA==} + + '@lexical/offset@0.35.0': + resolution: {integrity: sha512-DRE4Df6qYf2XiV6foh6KpGNmGAv2ANqt3oVXpyS6W8hTx3+cUuAA1APhCZmLNuU107um4zmHym7taCu6uXW5Yg==} + + '@lexical/overflow@0.35.0': + resolution: {integrity: sha512-B25YvnJQTGlZcrNv7b0PJBLWq3tl8sql497OHfYYLem7EOMPKKDGJScJAKM/91D4H/mMAsx5gnA/XgKobriuTg==} + + '@lexical/plain-text@0.35.0': + resolution: {integrity: sha512-lwBCUNMJf7Gujp2syVWMpKRahfbTv5Wq+H3HK1Q1gKH1P2IytPRxssCHvexw9iGwprSyghkKBlbF3fGpEdIJvQ==} + + '@lexical/react@0.35.0': + resolution: {integrity: sha512-uYAZSqumH8tRymMef+A0f2hQvMwplKK9DXamcefnk3vSNDHHqRWQXpiUo6kD+rKWuQmMbVa5RW4xRQebXEW+1A==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/rich-text@0.35.0': + resolution: {integrity: sha512-qEHu8g7vOEzz9GUz1VIUxZBndZRJPh9iJUFI+qTDHj+tQqnd5LCs+G9yz6jgNfiuWWpezTp0i1Vz/udNEuDPKQ==} + + '@lexical/selection@0.35.0': + resolution: {integrity: sha512-mMtDE7Q0nycXdFTTH/+ta6EBrBwxBB4Tg8QwsGntzQ1Cq//d838dpXpFjJOqHEeVHUqXpiuj+cBG8+bvz/rPRw==} + + '@lexical/table@0.35.0': + resolution: {integrity: sha512-9jlTlkVideBKwsEnEkqkdg7A3mije1SvmfiqoYnkl1kKJCLA5iH90ywx327PU0p+bdnURAytWUeZPXaEuEl2OA==} + + '@lexical/text@0.35.0': + resolution: {integrity: sha512-uaMh46BkysV8hK8wQwp5g/ByZW+2hPDt8ahAErxtf8NuzQem1FHG/f5RTchmFqqUDVHO3qLNTv4AehEGmXv8MA==} + + '@lexical/utils@0.35.0': + resolution: {integrity: sha512-2H393EYDnFznYCDFOW3MHiRzwEO5M/UBhtUjvTT+9kc+qhX4U3zc8ixQalo5UmZ5B2nh7L/inXdTFzvSRXtsRA==} + + '@lexical/yjs@0.35.0': + resolution: {integrity: sha512-3DSP7QpmTGYU9bN/yljP0PIao4tNIQtsR4ycauWNSawxs/GQCZtSmAPcLRnCm6qpqsDDjUtKjO/1Ej8FRp0m0w==} + peerDependencies: + yjs: '>=13.5.22' + + '@monaco-editor/loader@1.7.0': + resolution: {integrity: sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==} + + '@monaco-editor/react@4.7.0': + resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} + peerDependencies: + monaco-editor: '>= 0.25.0 < 1' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@mongodb-js/saslprep@1.4.0': + resolution: {integrity: sha512-ZHzx7Z3rdlWL1mECydvpryWN/ETXJiCxdgQKTAH+djzIPe77HdnSizKBDi1TVDXZjXyOj2IqEG/vPw71ULF06w==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + + '@next/eslint-plugin-next@15.1.5': + resolution: {integrity: sha512-3cCrXBybsqe94UxD6DBQCYCCiP9YohBMgZ5IzzPYHmPzj8oqNlhBii5b6o1HDDaRHdz2pVnSsAROCtrczy8O0g==} + + '@next/swc-darwin-arm64@15.5.7': + resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.5.7': + resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.5.7': + resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@15.5.7': + resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@15.5.7': + resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@15.5.7': + resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@15.5.7': + resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.5.7': + resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@payloadcms/db-mongodb@3.68.2': + resolution: {integrity: sha512-UMofU0wabU9gmelV1v6/6fyecuZXp7CplH4B2zHbsukl02zQ6nKN1I1JLcFSAmAAg/FPDz/HkpHKM4zNuI0Rig==} + peerDependencies: + payload: 3.68.2 + + '@payloadcms/graphql@3.68.2': + resolution: {integrity: sha512-7RjoVXWgHmod7Dps24Z/0G8vXA0QUa+C2BL68gOnKBoWHsPB7PcaUp7luPizkW3jjfZLKnGkhvrI6CiD60bDsg==} + hasBin: true + peerDependencies: + graphql: ^16.8.1 + payload: 3.68.2 + + '@payloadcms/next@3.68.2': + resolution: {integrity: sha512-Pb3ZVPe3XbAJ3Th8nbyBnuaCMP4ZlockMczl2fyrethJ379pXPPBGjrFECPoaHhKjQPIEUVxo7WZjY8Yf/qBmg==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + graphql: ^16.8.1 + next: ^15.4.8 + payload: 3.68.2 + + '@payloadcms/richtext-lexical@3.68.2': + resolution: {integrity: sha512-plPFLcCosONsuiTMIwyIZLTpxhIy1G7QajrejTZwRpXMCzB2xfLgSCDoiIg4KHLVIZV/UqSxtUrpYk7+zEpL2w==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + '@faceless-ui/modal': 3.0.0 + '@faceless-ui/scroll-info': 2.0.0 + '@payloadcms/next': 3.68.2 + payload: 3.68.2 + react: ^19.0.1 || ^19.1.2 || ^19.2.1 + react-dom: ^19.0.1 || ^19.1.2 || ^19.2.1 + + '@payloadcms/translations@3.68.2': + resolution: {integrity: sha512-HIfB6QYknjFGHs83ynUYyRgyGRKAEE7DRF0VMscwX0RtXNEtg3DMM+bCyTu5AZXr1hWrQ4xUrnVh7Vaj1yqWFQ==} + + '@payloadcms/ui@3.68.2': + resolution: {integrity: sha512-cKjdy0FucOTE+wxh5KZ7oTZQOvOxJFnmhfJd8av6HFoREt0r5kmnwc5rssdEgK2T1sJ2GcE4bZ0gVxB2vV6rCQ==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + next: ^15.2.6 || ^15.3.6 || ^15.4.8 || ^15.5.7 + payload: 3.68.2 + react: ^19.0.1 || ^19.1.2 || ^19.2.1 + react-dom: ^19.0.1 || ^19.1.2 || ^19.2.1 + + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@rushstack/eslint-patch@1.15.0': + resolution: {integrity: sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/acorn@4.0.6': + resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} + + '@types/busboy@1.5.4': + resolution: {integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/lodash@4.17.21': + resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@22.19.2': + resolution: {integrity: sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==} + + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react-transition-group@4.4.12': + resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} + peerDependencies: + '@types/react': '*' + + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@11.0.5': + resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} + + '@typescript-eslint/eslint-plugin@8.49.0': + resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.49.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.49.0': + resolution: {integrity: sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.49.0': + resolution: {integrity: sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.49.0': + resolution: {integrity: sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.49.0': + resolution: {integrity: sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.49.0': + resolution: {integrity: sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.49.0': + resolution: {integrity: sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.49.0': + resolution: {integrity: sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.49.0': + resolution: {integrity: sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.49.0': + resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.11.0: + resolution: {integrity: sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + b4a@1.7.3: + resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + bare-fs@4.5.2: + resolution: {integrity: sha512-veTnRzkb6aPHOvSKIOy60KzURfBdUflr5VReI+NSaPL6xf+XLdONQgZgpYvUuZLVQ8dCqxpBAudaOM1+KpAUxw==} + engines: {bare: '>=1.16.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-os@3.6.2: + resolution: {integrity: sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==} + engines: {bare: '>=1.14.0'} + + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.7.0: + resolution: {integrity: sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==} + peerDependencies: + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.3.2: + resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + body-scroll-lock@4.0.0-beta.0: + resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + bson-objectid@2.0.4: + resolution: {integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==} + + bson@6.10.4: + resolution: {integrity: sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==} + engines: {node: '>=16.20.1'} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001760: + resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + charenc@0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + console-table-printer@2.12.1: + resolution: {integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==} + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + croner@9.1.0: + resolution: {integrity: sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==} + engines: {node: '>=18.0'} + + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crypt@0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + + cssfilter@0.0.10: + resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + dataloader@2.2.3: + resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==} + + date-fns@3.6.0: + resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-next@15.1.5: + resolution: {integrity: sha512-Awm7iUJY8toOR+fU8yTxZnA7/LyOGUGOd6cENCuDfJ3gucHOSmLdOSGJ4u+nlrs8p5qXemua42bZmq+uOzxl6Q==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.39.1: + resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + fast-copy@3.0.2: + resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + file-type@19.3.0: + resolution: {integrity: sha512-mROwiKLZf/Kwa/2Rol+OOZQn1eyTkPB3ZTwC0ExY6OLFCbgxHYZvBm7xI77NvfZFMKBsmuXfmLJnD4eEftEhrA==} + engines: {node: '>=18'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + focus-trap@7.5.4: + resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graphql-http@1.22.4: + resolution: {integrity: sha512-OC3ucK988teMf+Ak/O+ZJ0N2ukcgrEurypp8ePyJFWq83VzwRAmHxxr+XxrMpxO/FIwI4a7m/Fzv3tWGJv0wPA==} + engines: {node: '>=12'} + peerDependencies: + graphql: '>=0.11 <=16' + + graphql-playground-html@1.6.30: + resolution: {integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==} + + graphql-scalars@1.22.2: + resolution: {integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==} + engines: {node: '>=10'} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + + graphql@16.12.0: + resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + + http-status@2.1.0: + resolution: {integrity: sha512-O5kPr7AW7wYd/BBiOezTwnVAnmSNFY+J7hlZD2X5IOxVBetjcHAiTXhzj0gMrnojQlwy+UT1/Y3H3vJ3UlmvLA==} + engines: {node: '>= 0.4.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + image-size@2.0.2: + resolution: {integrity: sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==} + engines: {node: '>=16.x'} + hasBin: true + + immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + ipaddr.js@2.2.0: + resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} + engines: {node: '>= 10'} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-arrayish@0.3.4: + resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jose@5.9.6: + resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-to-typescript@15.0.3: + resolution: {integrity: sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==} + engines: {node: '>=16.0.0'} + hasBin: true + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jsox@1.2.121: + resolution: {integrity: sha512-9Ag50tKhpTwS6r5wh3MJSAvpSof0UBr39Pto8OnzFT32Z/pAbxAsKHzyvsyMEHVslELvHyO/4/jaQELHk8wDcw==} + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + kareem@2.6.3: + resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==} + engines: {node: '>=12.0.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lexical@0.35.0: + resolution: {integrity: sha512-3VuV8xXhh5xJA6tzvfDvE0YBCMkIZUmxtRilJQDDdCgJCc+eut6qAv2qbN+pbqvarqcQqPN1UF+8YvsjmyOZpw==} + + lib0@0.2.114: + resolution: {integrity: sha512-gcxmNFzA4hv8UYi8j43uPlQ7CGcyMJ2KQb5kZASw6SnAKAf10hK12i2fjrS3Cl/ugZa5Ui6WwIu1/6MIXiHttQ==} + engines: {node: '>=16'} + hasBin: true + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + marked@14.0.0: + resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} + engines: {node: '>= 18'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + md5@2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-mdx-jsx@3.1.3: + resolution: {integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + memoize-one@6.0.0: + resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-mdx-jsx@3.0.1: + resolution: {integrity: sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + monaco-editor@0.55.1: + resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + + mongodb-connection-string-url@3.0.2: + resolution: {integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==} + + mongodb@6.16.0: + resolution: {integrity: sha512-D1PNcdT0y4Grhou5Zi/qgipZOYeWrhLEpk33n3nm6LGtz61jvO88WlrWCK/bigMjpnOdAUKKQwsGIl0NtWMyYw==} + engines: {node: '>=16.20.1'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.188.0 + '@mongodb-js/zstd': ^1.1.0 || ^2.0.0 + gcp-metadata: ^5.2.0 + kerberos: ^2.0.1 + mongodb-client-encryption: '>=6.0.0 <7' + snappy: ^7.2.2 + socks: ^2.7.1 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + + mongoose-paginate-v2@1.8.5: + resolution: {integrity: sha512-kFxhot+yw9KmpAGSSrF/o+f00aC2uawgNUbhyaM0USS9L7dln1NA77/pLg4lgOaRgXMtfgCENamjqZwIM1Zrig==} + engines: {node: '>=4.0.0'} + + mongoose@8.15.1: + resolution: {integrity: sha512-RhQ4DzmBi5BNGcS0w4u1vdMRIKcteXTCNzDt1j7XRcdWYBz1MjMjulBhPaeC5jBCHOD1yinuOFTTSOWLLGexWw==} + engines: {node: '>=16.20.1'} + + mpath@0.9.0: + resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} + engines: {node: '>=4.0.0'} + + mquery@5.0.0: + resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==} + engines: {node: '>=14.0.0'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + next@15.5.8: + resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-abi@3.85.0: + resolution: {integrity: sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==} + engines: {node: '>=10'} + + node-addon-api@6.1.0: + resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object-to-formdata@4.5.1: + resolution: {integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + payload@3.68.2: + resolution: {integrity: sha512-4ZdTJOUKSwUJXXMgEYIjonWmAgTxfnGTMuqQ1FZneSrZoZyjMOvXGiStEM0Ejd4zOlctUtAfum/gdgQC/CExyg==} + engines: {node: ^18.20.2 || >=20.9.0} + hasBin: true + peerDependencies: + graphql: ^16.8.1 + + peek-readable@5.4.2: + resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} + engines: {node: '>=14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-pretty@13.1.2: + resolution: {integrity: sha512-3cN0tCakkT4f3zo9RXDIhy6GTvtYD6bK4CRBLN9j3E/ePqN1tugAXD5rGVfoChW6s0hiek+eyYlLNqc/BG7vBQ==} + hasBin: true + + pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + + pino@9.14.0: + resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} + hasBin: true + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + engines: {node: '>=14'} + hasBin: true + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs-esm@7.0.2: + resolution: {integrity: sha512-D8NAthKSD7SGn748v+GLaaO6k08Mvpoqroa35PqIQC4gtUa8/Pb/k+r0m0NnGBVbHDP1gKZ2nVywqfMisRhV5A==} + engines: {node: '>=18'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-datepicker@7.6.0: + resolution: {integrity: sha512-9cQH6Z/qa4LrGhzdc3XoHbhrxNcMi9MKjZmYgF/1MNNaJwvdSjv3Xd+jjvrEEbKEf71ZgCA3n7fQbdwd70qCRw==} + peerDependencies: + react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + + react-dom@19.2.2: + resolution: {integrity: sha512-fhyD2BLrew6qYf4NNtHff1rLXvzR25rq49p+FeqByOazc6TcSi2n8EYulo5C1PbH+1uBW++5S1SG7FcUU6mlDg==} + peerDependencies: + react: ^19.2.2 + + react-error-boundary@3.1.4: + resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} + engines: {node: '>=10', npm: '>=6'} + peerDependencies: + react: '>=16.13.1' + + react-error-boundary@4.1.2: + resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} + peerDependencies: + react: '>=16.13.1' + + react-image-crop@10.1.8: + resolution: {integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==} + peerDependencies: + react: '>=16.13.1' + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-select@5.9.0: + resolution: {integrity: sha512-nwRKGanVHGjdccsnzhFte/PULziueZxGD8LL2WojON78Mvnq7LdAMEtu2frrwld1fr3geixg3iiMBIc/LLAZpw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + + react@19.2.2: + resolution: {integrity: sha512-BdOGOY8OKRBcgoDkwqA8Q5XvOIhoNx/Sh6BnGJlet2Abt0X5BK0BDrqGyQgLhAVjD2nAg5f6o01u/OPUhG022Q==} + engines: {node: '>=0.10.0'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + sanitize-filename@1.6.3: + resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + + sass@1.77.4: + resolution: {integrity: sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==} + engines: {node: '>=14.0.0'} + hasBin: true + + scheduler@0.25.0: + resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + scmp@2.1.0: + resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} + + secure-json-parse@4.1.0: + resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + sharp@0.32.6: + resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} + engines: {node: '>=14.15.0'} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + sift@17.1.3: + resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + simple-swizzle@0.2.4: + resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} + + simple-wcswidth@1.1.2: + resolution: {integrity: sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + sonic-boom@4.2.0: + resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + + sonner@1.7.4: + resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + streamx@2.23.0: + resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + + strtok3@8.1.0: + resolution: {integrity: sha512-ExzDvHYPj6F6QkSNe/JxSlBxTh3OrI6wrAIz53ulxo1c4hBJ1bT9C/JrAthEKHWG9riVH3Xzg7B03Oxty6S2Lw==} + engines: {node: '>=16'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-fs@3.1.1: + resolution: {integrity: sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + token-types@6.1.1: + resolution: {integrity: sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ==} + engines: {node: '>=14.16'} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + truncate-utf8-bytes@1.0.2: + resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-essentials@10.0.3: + resolution: {integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==} + peerDependencies: + typescript: '>=4.5.0' + peerDependenciesMeta: + typescript: + optional: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.20.3: + resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==} + engines: {node: '>=18.0.0'} + hasBin: true + + tsx@4.20.6: + resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + engines: {node: '>=18.0.0'} + hasBin: true + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript@5.7.3: + resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} + engines: {node: '>=14.17'} + hasBin: true + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici@7.10.0: + resolution: {integrity: sha512-u5otvFBOBZvmdjWLVW+5DAc9Nkq8f24g0O9oY7qw2JVIF1VocIFoyz9JFkuVOS2j41AufeO0xnlweJ2RLT8nGw==} + engines: {node: '>=20.18.1'} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-context-selector@2.0.0: + resolution: {integrity: sha512-owfuSmUNd3eNp3J9CdDl0kMgfidV+MkDvHPpvthN5ThqM+ibMccNE0k+Iq7TWC6JPFvGZqanqiGCuQx6DyV24g==} + peerDependencies: + react: '>=18.0.0' + scheduler: '>=0.19.0' + + use-isomorphic-layout-effect@1.2.1: + resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + utf8-byte-length@1.0.5: + resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xss@1.0.15: + resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==} + engines: {node: '>= 0.10.0'} + hasBin: true + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yjs@13.6.27: + resolution: {integrity: sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@apidevtools/json-schema-ref-parser@11.9.3': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@borewit/text-codec@0.1.1': {} + + '@date-fns/tz@1.2.0': {} + + '@dnd-kit/accessibility@3.1.1(react@19.2.2)': + dependencies: + react: 19.2.2 + tslib: 2.8.1 + + '@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@dnd-kit/accessibility': 3.1.1(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + tslib: 2.8.1 + + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + tslib: 2.8.1 + + '@dnd-kit/utilities@3.2.2(react@19.2.2)': + dependencies: + react: 19.2.2 + tslib: 2.8.1 + + '@emnapi/core@1.7.1': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.27.1 + '@babel/runtime': 7.28.4 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/hash@0.9.2': {} + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.2)': + dependencies: + '@babel/runtime': 7.28.4 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.2) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.2 + optionalDependencies: + '@types/react': 19.2.1 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.2.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.2)': + dependencies: + react: 19.2.2 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)': + dependencies: + eslint: 9.39.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.3': + dependencies: + ajv: 6.12.6 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.1': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@faceless-ui/modal@3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + body-scroll-lock: 4.0.0-beta.0 + focus-trap: 7.5.4 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + + '@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@faceless-ui/window-info@3.0.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@floating-ui/react@0.27.16(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@floating-ui/utils': 0.2.10 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + tabbable: 6.3.0 + + '@floating-ui/utils@0.2.10': {} + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.7.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jsdevtools/ono@7.1.3': {} + + '@lexical/clipboard@0.35.0': + dependencies: + '@lexical/html': 0.35.0 + '@lexical/list': 0.35.0 + '@lexical/selection': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/code@0.35.0': + dependencies: + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + prismjs: 1.30.0 + + '@lexical/devtools-core@0.35.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@lexical/html': 0.35.0 + '@lexical/link': 0.35.0 + '@lexical/mark': 0.35.0 + '@lexical/table': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@lexical/dragon@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/hashtag@0.35.0': + dependencies: + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/headless@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/history@0.35.0': + dependencies: + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/html@0.35.0': + dependencies: + '@lexical/selection': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/link@0.35.0': + dependencies: + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/list@0.35.0': + dependencies: + '@lexical/selection': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/mark@0.35.0': + dependencies: + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/markdown@0.35.0': + dependencies: + '@lexical/code': 0.35.0 + '@lexical/link': 0.35.0 + '@lexical/list': 0.35.0 + '@lexical/rich-text': 0.35.0 + '@lexical/text': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/offset@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/overflow@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/plain-text@0.35.0': + dependencies: + '@lexical/clipboard': 0.35.0 + '@lexical/selection': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/react@0.35.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.27)': + dependencies: + '@floating-ui/react': 0.27.16(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@lexical/devtools-core': 0.35.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@lexical/dragon': 0.35.0 + '@lexical/hashtag': 0.35.0 + '@lexical/history': 0.35.0 + '@lexical/link': 0.35.0 + '@lexical/list': 0.35.0 + '@lexical/mark': 0.35.0 + '@lexical/markdown': 0.35.0 + '@lexical/overflow': 0.35.0 + '@lexical/plain-text': 0.35.0 + '@lexical/rich-text': 0.35.0 + '@lexical/table': 0.35.0 + '@lexical/text': 0.35.0 + '@lexical/utils': 0.35.0 + '@lexical/yjs': 0.35.0(yjs@13.6.27) + lexical: 0.35.0 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 3.1.4(react@19.2.2) + transitivePeerDependencies: + - yjs + + '@lexical/rich-text@0.35.0': + dependencies: + '@lexical/clipboard': 0.35.0 + '@lexical/selection': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/selection@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/table@0.35.0': + dependencies: + '@lexical/clipboard': 0.35.0 + '@lexical/utils': 0.35.0 + lexical: 0.35.0 + + '@lexical/text@0.35.0': + dependencies: + lexical: 0.35.0 + + '@lexical/utils@0.35.0': + dependencies: + '@lexical/list': 0.35.0 + '@lexical/selection': 0.35.0 + '@lexical/table': 0.35.0 + lexical: 0.35.0 + + '@lexical/yjs@0.35.0(yjs@13.6.27)': + dependencies: + '@lexical/offset': 0.35.0 + '@lexical/selection': 0.35.0 + lexical: 0.35.0 + yjs: 13.6.27 + + '@monaco-editor/loader@1.7.0': + dependencies: + state-local: 1.0.7 + + '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@monaco-editor/loader': 1.7.0 + monaco-editor: 0.55.1 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@mongodb-js/saslprep@1.4.0': + dependencies: + sparse-bitfield: 3.0.3 + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@next/env@15.5.8': {} + + '@next/eslint-plugin-next@15.1.5': + dependencies: + fast-glob: 3.3.1 + + '@next/swc-darwin-arm64@15.5.7': + optional: true + + '@next/swc-darwin-x64@15.5.7': + optional: true + + '@next/swc-linux-arm64-gnu@15.5.7': + optional: true + + '@next/swc-linux-arm64-musl@15.5.7': + optional: true + + '@next/swc-linux-x64-gnu@15.5.7': + optional: true + + '@next/swc-linux-x64-musl@15.5.7': + optional: true + + '@next/swc-win32-arm64-msvc@15.5.7': + optional: true + + '@next/swc-win32-x64-msvc@15.5.7': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@payloadcms/db-mongodb@3.68.2(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))': + dependencies: + mongoose: 8.15.1 + mongoose-paginate-v2: 1.8.5 + payload: 3.68.2(graphql@16.12.0)(typescript@5.7.3) + prompts: 2.4.2 + uuid: 10.0.0 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + - supports-color + + '@payloadcms/graphql@3.68.2(graphql@16.12.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(typescript@5.7.3)': + dependencies: + graphql: 16.12.0 + graphql-scalars: 1.22.2(graphql@16.12.0) + payload: 3.68.2(graphql@16.12.0)(typescript@5.7.3) + pluralize: 8.0.0 + ts-essentials: 10.0.3(typescript@5.7.3) + tsx: 4.20.6 + transitivePeerDependencies: + - typescript + + '@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@payloadcms/graphql': 3.68.2(graphql@16.12.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(typescript@5.7.3) + '@payloadcms/translations': 3.68.2 + '@payloadcms/ui': 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) + busboy: 1.6.0 + dequal: 2.0.3 + file-type: 19.3.0 + graphql: 16.12.0 + graphql-http: 1.22.4(graphql@16.12.0) + graphql-playground-html: 1.6.30 + http-status: 2.1.0 + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + path-to-regexp: 6.3.0 + payload: 3.68.2(graphql@16.12.0)(typescript@5.7.3) + qs-esm: 7.0.2 + sass: 1.77.4 + uuid: 10.0.0 + transitivePeerDependencies: + - '@types/react' + - monaco-editor + - react + - react-dom + - supports-color + - typescript + + '@payloadcms/richtext-lexical@3.68.2(@faceless-ui/modal@3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3))(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)(yjs@13.6.27)': + dependencies: + '@faceless-ui/modal': 3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@lexical/clipboard': 0.35.0 + '@lexical/headless': 0.35.0 + '@lexical/html': 0.35.0 + '@lexical/link': 0.35.0 + '@lexical/list': 0.35.0 + '@lexical/mark': 0.35.0 + '@lexical/react': 0.35.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.27) + '@lexical/rich-text': 0.35.0 + '@lexical/selection': 0.35.0 + '@lexical/table': 0.35.0 + '@lexical/utils': 0.35.0 + '@payloadcms/next': 3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) + '@payloadcms/translations': 3.68.2 + '@payloadcms/ui': 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3) + '@types/uuid': 10.0.0 + acorn: 8.12.1 + bson-objectid: 2.0.4 + csstype: 3.1.3 + dequal: 2.0.3 + escape-html: 1.0.3 + jsox: 1.2.121 + lexical: 0.35.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-mdx-jsx: 3.1.3 + micromark-extension-mdx-jsx: 3.0.1 + payload: 3.68.2(graphql@16.12.0)(typescript@5.7.3) + qs-esm: 7.0.2 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 4.1.2(react@19.2.2) + ts-essentials: 10.0.3(typescript@5.7.3) + uuid: 10.0.0 + transitivePeerDependencies: + - '@types/react' + - monaco-editor + - next + - supports-color + - typescript + - yjs + + '@payloadcms/translations@3.68.2': + dependencies: + date-fns: 4.1.0 + + '@payloadcms/ui@3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.7.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.7.3)': + dependencies: + '@date-fns/tz': 1.2.0 + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + '@faceless-ui/modal': 3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/window-info': 3.0.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@monaco-editor/react': 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@payloadcms/translations': 3.68.2 + bson-objectid: 2.0.4 + date-fns: 4.1.0 + dequal: 2.0.3 + md5: 2.3.0 + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + object-to-formdata: 4.5.1 + payload: 3.68.2(graphql@16.12.0)(typescript@5.7.3) + qs-esm: 7.0.2 + react: 19.2.2 + react-datepicker: 7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-dom: 19.2.2(react@19.2.2) + react-image-crop: 10.1.8(react@19.2.2) + react-select: 5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + scheduler: 0.25.0 + sonner: 1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + ts-essentials: 10.0.3(typescript@5.7.3) + use-context-selector: 2.0.0(react@19.2.2)(scheduler@0.25.0) + uuid: 10.0.0 + transitivePeerDependencies: + - '@types/react' + - monaco-editor + - supports-color + - typescript + + '@pinojs/redact@0.4.0': {} + + '@rtsao/scc@1.1.0': {} + + '@rushstack/eslint-patch@1.15.0': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tokenizer/token@0.3.0': {} + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/acorn@4.0.6': + dependencies: + '@types/estree': 1.0.8 + + '@types/busboy@1.5.4': + dependencies: + '@types/node': 22.19.2 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + + '@types/estree@1.0.8': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/lodash@4.17.21': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@22.19.2': + dependencies: + undici-types: 6.21.0 + + '@types/parse-json@4.0.2': {} + + '@types/react-dom@19.2.1(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 + + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 + + '@types/react@19.2.1': + dependencies: + csstype: 3.2.3 + + '@types/trusted-types@2.0.7': + optional: true + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@types/uuid@10.0.0': {} + + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@11.0.5': + dependencies: + '@types/webidl-conversions': 7.0.3 + + '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.3))(eslint@9.39.1)(typescript@5.7.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/type-utils': 8.49.0(eslint@9.39.1)(typescript@5.7.3) + '@typescript-eslint/utils': 8.49.0(eslint@9.39.1)(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.49.0 + eslint: 9.39.1 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.7.3) + '@typescript-eslint/visitor-keys': 8.49.0 + debug: 4.4.3 + eslint: 9.39.1 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.49.0(typescript@5.7.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.7.3) + '@typescript-eslint/types': 8.49.0 + debug: 4.4.3 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.49.0': + dependencies: + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/visitor-keys': 8.49.0 + + '@typescript-eslint/tsconfig-utils@8.49.0(typescript@5.7.3)': + dependencies: + typescript: 5.7.3 + + '@typescript-eslint/type-utils@8.49.0(eslint@9.39.1)(typescript@5.7.3)': + dependencies: + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.7.3) + '@typescript-eslint/utils': 8.49.0(eslint@9.39.1)(typescript@5.7.3) + debug: 4.4.3 + eslint: 9.39.1 + ts-api-utils: 2.1.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.49.0': {} + + '@typescript-eslint/typescript-estree@8.49.0(typescript@5.7.3)': + dependencies: + '@typescript-eslint/project-service': 8.49.0(typescript@5.7.3) + '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.7.3) + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/visitor-keys': 8.49.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.49.0(eslint@9.39.1)(typescript@5.7.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.7.3) + eslint: 9.39.1 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.49.0': + dependencies: + '@typescript-eslint/types': 8.49.0 + eslint-visitor-keys: 4.2.1 + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.12.1: {} + + acorn@8.15.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + atomic-sleep@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.11.0: {} + + axobject-query@4.1.0: {} + + b4a@1.7.3: {} + + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.28.4 + cosmiconfig: 7.1.0 + resolve: 1.22.11 + + balanced-match@1.0.2: {} + + bare-events@2.8.2: {} + + bare-fs@4.5.2: + dependencies: + bare-events: 2.8.2 + bare-path: 3.0.0 + bare-stream: 2.7.0(bare-events@2.8.2) + bare-url: 2.3.2 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + optional: true + + bare-os@3.6.2: + optional: true + + bare-path@3.0.0: + dependencies: + bare-os: 3.6.2 + optional: true + + bare-stream@2.7.0(bare-events@2.8.2): + dependencies: + streamx: 2.23.0 + optionalDependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + optional: true + + bare-url@2.3.2: + dependencies: + bare-path: 3.0.0 + optional: true + + base64-js@1.5.1: {} + + binary-extensions@2.3.0: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + body-scroll-lock@4.0.0-beta.0: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + bson-objectid@2.0.4: {} + + bson@6.10.4: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001760: {} + + ccount@2.0.1: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + charenc@0.0.2: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chownr@1.1.4: {} + + ci-info@4.3.1: {} + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.4 + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + + colorette@2.0.20: {} + + commander@2.20.3: {} + + concat-map@0.0.1: {} + + console-table-printer@2.12.1: + dependencies: + simple-wcswidth: 1.1.2 + + convert-source-map@1.9.0: {} + + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.1 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + + croner@9.1.0: {} + + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crypt@0.0.2: {} + + cssfilter@0.0.10: {} + + csstype@3.1.3: {} + + csstype@3.2.3: {} + + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + dataloader@2.2.3: {} + + date-fns@3.6.0: {} + + date-fns@4.1.0: {} + + dateformat@4.6.3: {} + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.28.4 + csstype: 3.2.3 + + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + emoji-regex@9.2.2: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-next@15.1.5(eslint@9.39.1)(typescript@5.7.3): + dependencies: + '@next/eslint-plugin-next': 15.1.5 + '@rushstack/eslint-patch': 1.15.0 + '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.3))(eslint@9.39.1)(typescript@5.7.3) + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.7.3) + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.1) + eslint-plugin-react: 7.37.5(eslint@9.39.1) + eslint-plugin-react-hooks: 5.2.0(eslint@9.39.1) + optionalDependencies: + typescript: 5.7.3 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.39.1 + get-tsconfig: 4.13.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.15 + unrs-resolver: 1.11.1 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.7.3) + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.1 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.49.0(eslint@9.39.1)(typescript@5.7.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.1): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.11.0 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.39.1 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@5.2.0(eslint@9.39.1): + dependencies: + eslint: 9.39.1 + + eslint-plugin-react@7.37.5(eslint@9.39.1): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.39.1 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.1: + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.3 + '@eslint/js': 9.39.1 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + esutils@2.0.3: {} + + events-universal@1.0.1: + dependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + + expand-template@2.0.3: {} + + fast-copy@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-fifo@1.3.2: {} + + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-safe-stringify@2.1.1: {} + + fast-uri@3.1.0: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + file-type@19.3.0: + dependencies: + strtok3: 8.1.0 + token-types: 6.1.1 + uint8array-extras: 1.5.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-root@1.1.0: {} + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + focus-trap@7.5.4: + dependencies: + tabbable: 6.3.0 + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + fs-constants@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + get-tsconfig@4.8.1: + dependencies: + resolve-pkg-maps: 1.0.0 + + github-from-package@0.0.0: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + globals@14.0.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graphql-http@1.22.4(graphql@16.12.0): + dependencies: + graphql: 16.12.0 + + graphql-playground-html@1.6.30: + dependencies: + xss: 1.0.15 + + graphql-scalars@1.22.2(graphql@16.12.0): + dependencies: + graphql: 16.12.0 + tslib: 2.8.1 + + graphql@16.12.0: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + help-me@5.0.0: {} + + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + + http-status@2.1.0: {} + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + image-size@2.0.2: {} + + immutable@4.3.7: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + ipaddr.js@2.2.0: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.2.1: {} + + is-arrayish@0.3.4: {} + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-buffer@1.1.6: {} + + is-bun-module@2.0.0: + dependencies: + semver: 7.7.3 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-decimal@2.0.1: {} + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + isomorphic.js@0.2.5: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jose@5.9.6: {} + + joycon@3.1.1: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-to-typescript@15.0.3: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.9.3 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.21 + is-glob: 4.0.3 + js-yaml: 4.1.1 + lodash: 4.17.21 + minimist: 1.2.8 + prettier: 3.7.4 + tinyglobby: 0.2.15 + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + jsox@1.2.121: {} + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + kareem@2.6.3: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kleur@3.0.3: {} + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lexical@0.35.0: {} + + lib0@0.2.114: + dependencies: + isomorphic.js: 0.2.5 + + lines-and-columns@1.2.4: {} + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash@4.17.21: {} + + longest-streak@3.1.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + marked@14.0.0: {} + + math-intrinsics@1.1.0: {} + + md5@2.3.0: + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.1.3: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + memoize-one@6.0.0: {} + + memory-pager@1.5.0: {} + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.1: + dependencies: + '@types/acorn': 4.0.6 + '@types/estree': 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mimic-response@3.1.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + mkdirp-classic@0.5.3: {} + + monaco-editor@0.55.1: + dependencies: + dompurify: 3.2.7 + marked: 14.0.0 + + mongodb-connection-string-url@3.0.2: + dependencies: + '@types/whatwg-url': 11.0.5 + whatwg-url: 14.2.0 + + mongodb@6.16.0: + dependencies: + '@mongodb-js/saslprep': 1.4.0 + bson: 6.10.4 + mongodb-connection-string-url: 3.0.2 + + mongoose-paginate-v2@1.8.5: {} + + mongoose@8.15.1: + dependencies: + bson: 6.10.4 + kareem: 2.6.3 + mongodb: 6.16.0 + mpath: 0.9.0 + mquery: 5.0.0 + ms: 2.1.3 + sift: 17.1.3 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + - supports-color + + mpath@0.9.0: {} + + mquery@5.0.0: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + napi-build-utils@2.0.0: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): + dependencies: + '@next/env': 15.5.8 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001760 + postcss: 8.4.31 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + styled-jsx: 5.1.6(react@19.2.2) + optionalDependencies: + '@next/swc-darwin-arm64': 15.5.7 + '@next/swc-darwin-x64': 15.5.7 + '@next/swc-linux-arm64-gnu': 15.5.7 + '@next/swc-linux-arm64-musl': 15.5.7 + '@next/swc-linux-x64-gnu': 15.5.7 + '@next/swc-linux-x64-musl': 15.5.7 + '@next/swc-win32-arm64-msvc': 15.5.7 + '@next/swc-win32-x64-msvc': 15.5.7 + sass: 1.77.4 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-abi@3.85.0: + dependencies: + semver: 7.7.3 + + node-addon-api@6.1.0: {} + + normalize-path@3.0.0: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object-to-formdata@4.5.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + on-exit-leak-free@2.1.2: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.2.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-to-regexp@6.3.0: {} + + path-type@4.0.0: {} + + payload@3.68.2(graphql@16.12.0)(typescript@5.7.3): + dependencies: + '@next/env': 15.5.8 + '@payloadcms/translations': 3.68.2 + '@types/busboy': 1.5.4 + ajv: 8.17.1 + bson-objectid: 2.0.4 + busboy: 1.6.0 + ci-info: 4.3.1 + console-table-printer: 2.12.1 + croner: 9.1.0 + dataloader: 2.2.3 + deepmerge: 4.3.1 + file-type: 19.3.0 + get-tsconfig: 4.8.1 + graphql: 16.12.0 + http-status: 2.1.0 + image-size: 2.0.2 + ipaddr.js: 2.2.0 + jose: 5.9.6 + json-schema-to-typescript: 15.0.3 + minimist: 1.2.8 + path-to-regexp: 6.3.0 + pino: 9.14.0 + pino-pretty: 13.1.2 + pluralize: 8.0.0 + qs-esm: 7.0.2 + sanitize-filename: 1.6.3 + scmp: 2.1.0 + ts-essentials: 10.0.3(typescript@5.7.3) + tsx: 4.20.3 + undici: 7.10.0 + uuid: 10.0.0 + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + + peek-readable@5.4.2: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-pretty@13.1.2: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pump: 3.0.3 + secure-json-parse: 4.1.0 + sonic-boom: 4.2.0 + strip-json-comments: 5.0.3 + + pino-std-serializers@7.0.0: {} + + pino@9.14.0: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + + pluralize@8.0.0: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.85.0 + pump: 3.0.3 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 + + prelude-ls@1.2.1: {} + + prettier@3.7.4: {} + + prismjs@1.30.0: {} + + process-warning@5.0.0: {} + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + qs-esm@7.0.2: {} + + queue-microtask@1.2.3: {} + + quick-format-unescaped@4.0.4: {} + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + react-datepicker@7.6.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): + dependencies: + '@floating-ui/react': 0.27.16(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + clsx: 2.1.1 + date-fns: 3.6.0 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + react-dom@19.2.2(react@19.2.2): + dependencies: + react: 19.2.2 + scheduler: 0.27.0 + + react-error-boundary@3.1.4(react@19.2.2): + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.2 + + react-error-boundary@4.1.2(react@19.2.2): + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.2 + + react-image-crop@10.1.8(react@19.2.2): + dependencies: + react: 19.2.2 + + react-is@16.13.1: {} + + react-select@5.9.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): + dependencies: + '@babel/runtime': 7.28.4 + '@emotion/cache': 11.14.0 + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.2) + '@floating-ui/dom': 1.7.4 + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) + memoize-one: 6.0.0 + prop-types: 15.8.1 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.1)(react@19.2.2) + transitivePeerDependencies: + - '@types/react' + - supports-color + + react-transition-group@4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2): + dependencies: + '@babel/runtime': 7.28.4 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + react@19.2.2: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + real-require@0.2.0: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.5: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safe-stable-stringify@2.5.0: {} + + sanitize-filename@1.6.3: + dependencies: + truncate-utf8-bytes: 1.0.2 + + sass@1.77.4: + dependencies: + chokidar: 3.6.0 + immutable: 4.3.7 + source-map-js: 1.2.1 + + scheduler@0.25.0: {} + + scheduler@0.27.0: {} + + scmp@2.1.0: {} + + secure-json-parse@4.1.0: {} + + semver@6.3.1: {} + + semver@7.7.3: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + sharp@0.32.6: + dependencies: + color: 4.2.3 + detect-libc: 2.1.2 + node-addon-api: 6.1.0 + prebuild-install: 7.1.3 + semver: 7.7.3 + simple-get: 4.0.1 + tar-fs: 3.1.1 + tunnel-agent: 0.6.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + sharp@0.34.5: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + sift@17.1.3: {} + + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + + simple-wcswidth@1.1.2: {} + + sisteransi@1.0.5: {} + + sonic-boom@4.2.0: + dependencies: + atomic-sleep: 1.0.0 + + sonner@1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2): + dependencies: + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + source-map-js@1.2.1: {} + + source-map@0.5.7: {} + + sparse-bitfield@3.0.3: + dependencies: + memory-pager: 1.5.0 + + split2@4.2.0: {} + + stable-hash@0.0.5: {} + + state-local@1.0.7: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + streamsearch@1.1.0: {} + + streamx@2.23.0: + dependencies: + events-universal: 1.0.1 + fast-fifo: 1.3.2 + text-decoder: 1.2.3 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-bom@3.0.0: {} + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + strip-json-comments@5.0.3: {} + + strtok3@8.1.0: + dependencies: + '@tokenizer/token': 0.3.0 + peek-readable: 5.4.2 + + styled-jsx@5.1.6(react@19.2.2): + dependencies: + client-only: 0.0.1 + react: 19.2.2 + + stylis@4.2.0: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tabbable@6.3.0: {} + + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.3 + tar-stream: 2.2.0 + + tar-fs@3.1.1: + dependencies: + pump: 3.0.3 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 4.5.2 + bare-path: 3.0.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tar-stream@3.1.7: + dependencies: + b4a: 1.7.3 + fast-fifo: 1.3.2 + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + text-decoder@1.2.3: + dependencies: + b4a: 1.7.3 + transitivePeerDependencies: + - react-native-b4a + + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + token-types@6.1.1: + dependencies: + '@borewit/text-codec': 0.1.1 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + + truncate-utf8-bytes@1.0.2: + dependencies: + utf8-byte-length: 1.0.5 + + ts-api-utils@2.1.0(typescript@5.7.3): + dependencies: + typescript: 5.7.3 + + ts-essentials@10.0.3(typescript@5.7.3): + optionalDependencies: + typescript: 5.7.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + tsx@4.20.3: + dependencies: + esbuild: 0.25.12 + get-tsconfig: 4.8.1 + optionalDependencies: + fsevents: 2.3.3 + + tsx@4.20.6: + dependencies: + esbuild: 0.25.12 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript@5.7.3: {} + + uint8array-extras@1.5.0: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + undici@7.10.0: {} + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-context-selector@2.0.0(react@19.2.2)(scheduler@0.25.0): + dependencies: + react: 19.2.2 + scheduler: 0.25.0 + + use-isomorphic-layout-effect@1.2.1(@types/react@19.2.1)(react@19.2.2): + dependencies: + react: 19.2.2 + optionalDependencies: + '@types/react': 19.2.1 + + utf8-byte-length@1.0.5: {} + + util-deprecate@1.0.2: {} + + uuid@10.0.0: {} + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + webidl-conversions@7.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrappy@1.0.2: {} + + ws@8.18.3: {} + + xss@1.0.15: + dependencies: + commander: 2.20.3 + cssfilter: 0.0.10 + + yaml@1.10.2: {} + + yjs@13.6.27: + dependencies: + lib0: 0.2.114 + + yocto-queue@0.1.0: {} + + zwitch@2.0.4: {} diff --git a/examples/tailwind-shadcn-ui/package.json b/examples/tailwind-shadcn-ui/package.json index 4c95dd8007e..07db4247f62 100644 --- a/examples/tailwind-shadcn-ui/package.json +++ b/examples/tailwind-shadcn-ui/package.json @@ -21,7 +21,7 @@ "clsx": "^2.1.1", "cross-env": "^7.0.3", "lucide-react": "^0.376.0", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "beta", "react": "^19.2.1", "react-dom": "^19.2.1", diff --git a/examples/tailwind-shadcn-ui/pnpm-lock.yaml b/examples/tailwind-shadcn-ui/pnpm-lock.yaml index da666f07dfd..c33a140671b 100644 --- a/examples/tailwind-shadcn-ui/pnpm-lock.yaml +++ b/examples/tailwind-shadcn-ui/pnpm-lock.yaml @@ -1,3520 +1,3461 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - '@payloadcms/db-mongodb': - specifier: beta - version: 3.0.0-beta.19(payload@3.0.0-beta.19) - '@payloadcms/next': - specifier: beta - version: 3.0.0-beta.19(@types/react@18.3.1)(file-type@16.5.4)(graphql@16.8.1)(http-status@1.6.2)(monaco-editor@0.48.0)(next@14.3.0-canary.7)(payload@3.0.0-beta.19)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.2) - '@payloadcms/richtext-lexical': - specifier: beta - version: 3.0.0-beta.19(@lexical/clipboard@0.13.1)(@payloadcms/next@3.0.0-beta.19)(@payloadcms/translations@3.0.0-beta.19)(@payloadcms/ui@3.0.0-beta.19)(payload@3.0.0-beta.19)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5)(yjs@13.6.15) - class-variance-authority: - specifier: ^0.7.0 - version: 0.7.0 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - cross-env: - specifier: ^7.0.3 - version: 7.0.3 - lucide-react: - specifier: ^0.376.0 - version: 0.376.0(react@18.3.1) - next: - specifier: 14.3.0-canary.7 - version: 14.3.0-canary.7(react-dom@18.3.1)(react@18.3.1) - payload: - specifier: beta - version: 3.0.0-beta.19(@swc/core@1.4.17)(@swc/types@0.1.6)(graphql@16.8.1) - react: - specifier: ^18.2.0 - version: 18.3.1 - react-dom: - specifier: ^18.2.0 - version: 18.3.1(react@18.3.1) - sharp: - specifier: 0.32.6 - version: 0.32.6 - tailwind-merge: - specifier: ^2.3.0 - version: 2.3.0 - tailwindcss-animate: - specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.3) - -devDependencies: - '@types/node': - specifier: ^20.11.25 - version: 20.12.7 - '@types/react': - specifier: ^18.2.64 - version: 18.3.1 - '@types/react-dom': - specifier: ^18.2.21 - version: 18.3.0 - autoprefixer: - specifier: ^10.4.19 - version: 10.4.19(postcss@8.4.38) - dotenv: - specifier: ^16.4.5 - version: 16.4.5 - postcss: - specifier: ^8.4.38 - version: 8.4.38 - tailwindcss: - specifier: ^3.4.3 - version: 3.4.3 - tsx: - specifier: ^4.7.1 - version: 4.7.3 - typescript: - specifier: ^5.4.2 - version: 5.4.5 +importers: + + .: + dependencies: + '@payloadcms/db-mongodb': + specifier: beta + version: 3.0.0-beta.135(payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)) + '@payloadcms/next': + specifier: beta + version: 3.0.0-beta.135(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + '@payloadcms/richtext-lexical': + specifier: beta + version: 3.0.0-beta.135(9b4a47f79fb2e59c857749218ee42c77) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + lucide-react: + specifier: ^0.376.0 + version: 0.376.0(react@19.2.2) + next: + specifier: ^15.4.9 + version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + payload: + specifier: beta + version: 3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + react: + specifier: ^19.2.1 + version: 19.2.2 + react-dom: + specifier: ^19.2.1 + version: 19.2.2(react@19.2.2) + sharp: + specifier: 0.32.6 + version: 0.32.6 + tailwind-merge: + specifier: ^2.3.0 + version: 2.6.0 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.19(tsx@4.21.0)) + devDependencies: + '@types/node': + specifier: ^20.11.25 + version: 20.19.26 + '@types/react': + specifier: 19.2.1 + version: 19.2.1 + '@types/react-dom': + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) + autoprefixer: + specifier: ^10.4.19 + version: 10.4.22(postcss@8.5.6) + dotenv: + specifier: ^16.4.5 + version: 16.6.1 + postcss: + specifier: ^8.4.38 + version: 8.5.6 + tailwindcss: + specifier: ^3.4.3 + version: 3.4.19(tsx@4.21.0) + tsx: + specifier: ^4.7.1 + version: 4.21.0 + typescript: + specifier: ^5.4.2 + version: 5.9.3 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@apidevtools/json-schema-ref-parser@11.9.3': + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} + engines: {node: '>= 16'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@borewit/text-codec@0.1.1': + resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} + + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.0.8': + resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/sortable@7.0.2': + resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} + peerDependencies: + '@dnd-kit/core': ^6.0.7 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + + '@emotion/css@11.13.5': + resolution: {integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + peerDependencies: + react: '>=16.8.0' + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.1': + resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.27.1': + resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.27.1': + resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.27.1': + resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.27.1': + resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.1': + resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.1': + resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.1': + resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.27.1': + resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.27.1': + resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.1': + resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.27.1': + resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.1': + resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.1': + resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.1': + resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.1': + resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.1': + resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.1': + resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.1': + resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.1': + resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.1': + resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.1': + resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.1': + resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.1': + resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.1': + resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.1': + resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@faceless-ui/modal@3.0.0-beta.2': + resolution: {integrity: sha512-UmXvz7Iw3KMO4Pm3llZczU4uc5pPQDb6rdqwoBvYDFgWvkraOAHKx0HxSZgwqQvqOhn8joEFBfFp6/Do2562ow==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + + '@faceless-ui/scroll-info@2.0.0-beta.0': + resolution: {integrity: sha512-pUBhQP8vduA7rVndNsjhaCcds1BykA/Q4iV23JWijU6ZFL/M3Fm9P3ypDS+0VVxolqemNhw8S3FXPwZGgjH4Rw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + + '@faceless-ui/window-info@3.0.0-beta.0': + resolution: {integrity: sha512-Qs8xRA+fl4sU2aFVe9xawxfi5TVZ9VTPuhdQpx9aSv7U5a2F0AXwT61lJfnaJ9Flm8tOcxzq67p8cVZsXNCVeQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc.0 + + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.26.28': + resolution: {integrity: sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@lexical/clipboard@0.20.0': + resolution: {integrity: sha512-oHmb9kSVHjeFCd2q8VrEXW22doUHMJ6cGXqo7Ican7Ljl4/9OgRWr+cq55yntoSaJfCrRYkTiZCLDejF2ciSiA==} + + '@lexical/code@0.20.0': + resolution: {integrity: sha512-zFsVGuzIn4CQxEnlW4AG/Hq6cyATVZ4fZTxozE/f5oK4vDPvnY/goRxrzSuAMX73A/HRX3kTEzMDcm4taRM3Mg==} + + '@lexical/devtools-core@0.20.0': + resolution: {integrity: sha512-/CnL+Dfpzw4koy2BTdUICkvrCkMIYG8Y73KB/S1Bt5UzJpD+PV300puWJ0NvUvAj24H78r73jxvK2QUG67Tdaw==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/dragon@0.20.0': + resolution: {integrity: sha512-3DAHF8mSKiPZtXCqu2P8ynSwS3fGXzg4G/V0lXNjBxhmozjzUzWZRWIWtmTlWdEu9GXsoyeM3agcaxyDPJJwkA==} + + '@lexical/hashtag@0.20.0': + resolution: {integrity: sha512-ldOP/d9tA6V9qvLyr3mRYkcYY5ySOHJ2BFOW/jZPxQcj6lWafS8Lk7XdMUpHHDjRpY2Hizsi5MHJkIqFglYXbw==} + + '@lexical/headless@0.20.0': + resolution: {integrity: sha512-PZ9Yxud7UOpVoq3oJ1wb3wb7NHyFt8XLc1IhdNAzTzbZ+L6c9lyomgBFvDs11u/3t9vjtLxGbzkzYKryQE80Ig==} + + '@lexical/history@0.20.0': + resolution: {integrity: sha512-dXtIS31BU6RmLX2KwLAi1EgGl+USeyi+rshh19azACXHPFqONZgPd2t21LOLSFn7C1/W+cSp/kqVDlQVbZUZRA==} + + '@lexical/html@0.20.0': + resolution: {integrity: sha512-ob7QHkEv+mhaZjlurDj90UmEyN9G4rzBPR5QV42PLnu1qMSviMEdI5V3a5/A5aFf/FDDQ+0GAgWBFnA/MEDczQ==} + + '@lexical/link@0.20.0': + resolution: {integrity: sha512-zicDcfgRZPRFZ8WOZv5er0Aqkde+i7QoFVkLQD4dNLLORjoMSJOISJH6VEdjBl3k7QJTxbfrt+xT5d/ZsAN5GA==} + + '@lexical/list@0.20.0': + resolution: {integrity: sha512-ufSse8ui3ooUe0HA/yF/9STrG8wYhIDLMRhELOw80GFCkPJaxs6yRvjfmJooH5IC88rpUJ5XXFFiZKfGxEZLEw==} + + '@lexical/mark@0.20.0': + resolution: {integrity: sha512-1P2izmkgZ4VDp+49rWO1KfWivL5aA30y5kkYbFZ/CS05fgbO7ogMjLSajpz+RN/zzW79v3q4YfikrMgaD23InA==} + + '@lexical/markdown@0.20.0': + resolution: {integrity: sha512-ZoGsECejp9z6MEvc8l81b1h1aWbB3sTq6xOFeUTbDL5vKpA67z5CmQQLi0uZWrygrbO9dSE3Q/JGcodUrczxbw==} + + '@lexical/offset@0.20.0': + resolution: {integrity: sha512-VMhxsxxDGnpVw0jgC8UlDf0Q2RHIHbS49uZgs3l9nP+O+G8s3b76Ta4Tb+iJOK2FY6874/TcQMbSuXGhfpQk8A==} + + '@lexical/overflow@0.20.0': + resolution: {integrity: sha512-z4lElzLm1FVifc7bzBZN4VNKeTuwygpyHQvCJVWXzF2Kbvex43PEYMi8u4A83idVqbmzbyBLASwUJS0voLoPLw==} + + '@lexical/plain-text@0.20.0': + resolution: {integrity: sha512-LvoC+9mm2Im1iO8GgtgaqSfW0T3mIE5GQl1xGxbVNdANmtHmBgRAJn2KfQm1XHZP6zydLRMhZkzC+jfInh2yfQ==} + + '@lexical/react@0.20.0': + resolution: {integrity: sha512-5QbN5AFtZ9efXxU/M01ADhUZgthR0e8WKi5K/w5EPpWtYFDPQnUte3rKUjYJ7uwG1iwcvaCpuMbxJjHQ+i6pDQ==} + peerDependencies: + react: '>=17.x' + react-dom: '>=17.x' + + '@lexical/rich-text@0.20.0': + resolution: {integrity: sha512-BR1pACdMA+Ymef0f5EN1y+9yP8w7S+9MgmBP1yjr3w4KdqRnfSaGWyxwcHU8eA+zu16QfivpB6501VJ90YeuXw==} + + '@lexical/selection@0.20.0': + resolution: {integrity: sha512-YnkH5UCMNN/em95or/6uwAV31vcENh1Roj+JOg5KD+gJuA7VGdDCy0vZl/o0+1badXozeZ2VRxXNC6JSK7T4+A==} + + '@lexical/table@0.20.0': + resolution: {integrity: sha512-qHuK2rvQUoQDx62YpvJE3Ev4yK9kjRFo79IDBapxrhoXg/wCGQOjMBzVD3G5PWkhyl/GDnww80GwYjLloQLQzg==} + + '@lexical/text@0.20.0': + resolution: {integrity: sha512-Fu64i5CIlEOlgucSdp9XFqB2XqoRsw4at76n93+6RF4+LgGDnu4nLXQVCVxNmLcGyh2WgczuTpnk5P2mHNAIUA==} + + '@lexical/utils@0.20.0': + resolution: {integrity: sha512-sXIa2nowrNxY8VcjjuxZbJ/HovIql8bmInNaxBR03JAYfqMiL5I5/dYgjOQJV49NJnuR1uTY2GwVxVTXCTFUCw==} + + '@lexical/yjs@0.20.0': + resolution: {integrity: sha512-TiHNhu2VkhXN69V+fXVS3xjOQ6aLnheQUGwOAhuFkDPL3VLCb0yl2Mgydpayn+3Grwii4ZBHcF7oCC84GiU5bw==} + peerDependencies: + yjs: '>=13.5.22' + + '@monaco-editor/loader@1.7.0': + resolution: {integrity: sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==} + + '@monaco-editor/react@4.6.0': + resolution: {integrity: sha512-RFkU9/i7cN2bsq/iTkurMWOEErmYcY6JiQI3Jn+WeR/FGISH8JbHERjpS9oRuSOPvDMJI0Z8nJeKkbOs9sBYQw==} + peerDependencies: + monaco-editor: '>= 0.25.0 < 1' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + + '@mongodb-js/saslprep@1.4.0': + resolution: {integrity: sha512-ZHzx7Z3rdlWL1mECydvpryWN/ETXJiCxdgQKTAH+djzIPe77HdnSizKBDi1TVDXZjXyOj2IqEG/vPw71ULF06w==} + + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + + '@next/swc-darwin-arm64@15.5.7': + resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.5.7': + resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.5.7': + resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@15.5.7': + resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@15.5.7': + resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@15.5.7': + resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@15.5.7': + resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.5.7': + resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@payloadcms/db-mongodb@3.0.0-beta.135': + resolution: {integrity: sha512-C3He4U+7bc4NgbmFJyWJUNSEHQHmaUAUSAJKMHaFXQoCbJSh3SlXuUHLfe02a+xvwf9GWeENaMj0nHAn2h8lDw==} + peerDependencies: + payload: 3.0.0-beta.135 + + '@payloadcms/graphql@3.0.0-beta.135': + resolution: {integrity: sha512-Qzkjr3j08OerHJjkXU6SvFvaFk3iI+3fGeeGVWrCaHh/bHXx0hJv4/GoR5Os808EDdV77myRHiUiJmNjTGIX/Q==} + hasBin: true + peerDependencies: + graphql: ^16.8.1 + payload: 3.0.0-beta.135 + + '@payloadcms/next@3.0.0-beta.135': + resolution: {integrity: sha512-jImEMsdCZunVlN2IxhTPd5IXdYSm0+OJUcg+4m8qKiP+DMub9+cDfsG/wTKqiFSshj+7W/ZHcf4xkmqM2R88IQ==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + graphql: ^16.8.1 + next: ^15.0.0 + payload: 3.0.0-beta.135 + + '@payloadcms/richtext-lexical@3.0.0-beta.135': + resolution: {integrity: sha512-6wPOBTDjTlktwAZJCsSChpw92iyfBYH34W5ApaTSZ0S87Nuoib2/hUI5yy1ET9Jwjb3oD/m9oKWqtv9orwU3Xg==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + '@faceless-ui/modal': 3.0.0-beta.2 + '@faceless-ui/scroll-info': 2.0.0-beta.0 + '@lexical/headless': 0.20.0 + '@lexical/link': 0.20.0 + '@lexical/list': 0.20.0 + '@lexical/mark': 0.20.0 + '@lexical/markdown': 0.20.0 + '@lexical/react': 0.20.0 + '@lexical/rich-text': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/table': 0.20.0 + '@lexical/utils': 0.20.0 + '@payloadcms/next': 3.0.0-beta.135 + lexical: 0.20.0 + payload: 3.0.0-beta.135 + react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + + '@payloadcms/translations@3.0.0-beta.135': + resolution: {integrity: sha512-wpD+S9DN019idNgPPQtK64bjFPEspYwapwX7oYEIq477gugyhLjqzotAKgpqV7t0loZzu9bGtLWvOibFj09ClQ==} + + '@payloadcms/ui@3.0.0-beta.135': + resolution: {integrity: sha512-DregO0mTm2Spz3GbWLnEuxBJwwJjESAFXy9nDy0IG/i8cGIqdnLfBFeJh1+48VGKbpumWd7Csyo1/0n2VrgE3A==} + engines: {node: ^18.20.2 || >=20.9.0} + peerDependencies: + next: ^15.0.0 + payload: 3.0.0-beta.135 + react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@types/acorn@4.0.6': + resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} + + '@types/busboy@1.5.4': + resolution: {integrity: sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/lodash@4.17.21': + resolution: {integrity: sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@20.19.26': + resolution: {integrity: sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg==} + + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react-transition-group@4.4.12': + resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} + peerDependencies: + '@types/react': '*' + + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@11.0.5': + resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==} + + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + autoprefixer@10.4.22: + resolution: {integrity: sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + b4a@1.7.3: + resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} + peerDependencies: + react-native-b4a: '*' + peerDependenciesMeta: + react-native-b4a: + optional: true + + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + + bare-events@2.8.2: + resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} + peerDependencies: + bare-abort-controller: '*' + peerDependenciesMeta: + bare-abort-controller: + optional: true + + bare-fs@4.5.2: + resolution: {integrity: sha512-veTnRzkb6aPHOvSKIOy60KzURfBdUflr5VReI+NSaPL6xf+XLdONQgZgpYvUuZLVQ8dCqxpBAudaOM1+KpAUxw==} + engines: {bare: '>=1.16.0'} + peerDependencies: + bare-buffer: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + + bare-os@3.6.2: + resolution: {integrity: sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==} + engines: {bare: '>=1.14.0'} + + bare-path@3.0.0: + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + + bare-stream@2.7.0: + resolution: {integrity: sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==} + peerDependencies: + bare-buffer: '*' + bare-events: '*' + peerDependenciesMeta: + bare-buffer: + optional: true + bare-events: + optional: true + + bare-url@2.3.2: + resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.9.6: + resolution: {integrity: sha512-v9BVVpOTLB59C9E7aSnmIF8h7qRsFpx+A2nugVMTszEOMcfjlZMsXRm4LF23I3Z9AJxc8ANpIvzbzONoX9VJlg==} + hasBin: true + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + body-scroll-lock@4.0.0-beta.0: + resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bson-objectid@2.0.4: + resolution: {integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==} + + bson@6.10.4: + resolution: {integrity: sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==} + engines: {node: '>=16.20.1'} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + caniuse-lite@1.0.30001760: + resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + charenc@0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + console-table-printer@2.12.1: + resolution: {integrity: sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==} + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + croner@9.0.0: + resolution: {integrity: sha512-onMB0OkDjkXunhdW9htFjEhqrD54+M94i6ackoUkjHKbRnXdyEyKRelp4nJ1kAz32+s27jP1FsebpJCVl0BsvA==} + engines: {node: '>=18.0'} + + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crypt@0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssfilter@0.0.10: + resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + dataloader@2.2.2: + resolution: {integrity: sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==} + + date-fns@3.6.0: + resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.27.1: + resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + events-universal@1.0.1: + resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + fast-copy@3.0.2: + resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-type@19.3.0: + resolution: {integrity: sha512-mROwiKLZf/Kwa/2Rol+OOZQn1eyTkPB3ZTwC0ExY6OLFCbgxHYZvBm7xI77NvfZFMKBsmuXfmLJnD4eEftEhrA==} + engines: {node: '>=18'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + + focus-trap@7.5.4: + resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + graphql-http@1.22.4: + resolution: {integrity: sha512-OC3ucK988teMf+Ak/O+ZJ0N2ukcgrEurypp8ePyJFWq83VzwRAmHxxr+XxrMpxO/FIwI4a7m/Fzv3tWGJv0wPA==} + engines: {node: '>=12'} + peerDependencies: + graphql: '>=0.11 <=16' + + graphql-playground-html@1.6.30: + resolution: {integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==} + + graphql-scalars@1.22.2: + resolution: {integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==} + engines: {node: '>=10'} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + + graphql@16.12.0: + resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + + http-status@1.6.2: + resolution: {integrity: sha512-oUExvfNckrpTpDazph7kNG8sQi5au3BeTo0idaZFXEhTaJKu7GNJCLHI0rYY2wljm548MSTM+Ljj/c6anqu2zQ==} + engines: {node: '>= 0.4.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + image-size@1.2.1: + resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} + engines: {node: '>=16.x'} + hasBin: true + + immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-arrayish@0.3.4: + resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + + jose@5.9.6: + resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-to-typescript@15.0.3: + resolution: {integrity: sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==} + engines: {node: '>=16.0.0'} + hasBin: true + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + kareem@2.6.3: + resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==} + engines: {node: '>=12.0.0'} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + lexical@0.20.0: + resolution: {integrity: sha512-lJEHLFACXqRf3u/VlIOu9T7MJ51O4la92uOBwiS9Sx+juDK3Nrru5Vgl1aUirV1qK8XEM3h6Org2HcrsrzZ3ZA==} + + lib0@0.2.114: + resolution: {integrity: sha512-gcxmNFzA4hv8UYi8j43uPlQ7CGcyMJ2KQb5kZASw6SnAKAf10hK12i2fjrS3Cl/ugZa5Ui6WwIu1/6MIXiHttQ==} + engines: {node: '>=16'} + hasBin: true + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lucide-react@0.376.0: + resolution: {integrity: sha512-g91IX3ERD6yUR1TL2dsL4BkcGygpZz/EsqjAeL/kcRQV0EApIOr/9eBfKhYOVyQIcGGuotFGjF3xKLHMEz+b7g==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 + + marked@14.0.0: + resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} + engines: {node: '>= 18'} + hasBin: true + + md5@2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + + mdast-util-from-markdown@2.0.2: + resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + + mdast-util-mdx-jsx@3.1.3: + resolution: {integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + memoize-one@6.0.0: + resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-mdx-jsx@3.0.1: + resolution: {integrity: sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + monaco-editor@0.55.1: + resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + + mongodb-connection-string-url@3.0.2: + resolution: {integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==} + + mongodb@6.10.0: + resolution: {integrity: sha512-gP9vduuYWb9ZkDM546M+MP2qKVk5ZG2wPF63OvSRuUbqCR+11ZCAE1mOfllhlAG0wcoJY5yDL/rV3OmYEwXIzg==} + engines: {node: '>=16.20.1'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.188.0 + '@mongodb-js/zstd': ^1.1.0 + gcp-metadata: ^5.2.0 + kerberos: ^2.0.1 + mongodb-client-encryption: '>=6.0.0 <7' + snappy: ^7.2.2 + socks: ^2.7.1 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + + mongoose-aggregate-paginate-v2@1.1.2: + resolution: {integrity: sha512-Ai478tHedZy3U2ITBEp2H4rQEviRan3TK4p/umlFqIzgPF1R0hNKvzzQGIb1l2h+Z32QLU3NqaoWKu4vOOUElQ==} + engines: {node: '>=4.0.0'} + + mongoose-paginate-v2@1.8.5: + resolution: {integrity: sha512-kFxhot+yw9KmpAGSSrF/o+f00aC2uawgNUbhyaM0USS9L7dln1NA77/pLg4lgOaRgXMtfgCENamjqZwIM1Zrig==} + engines: {node: '>=4.0.0'} + + mongoose@8.8.1: + resolution: {integrity: sha512-l7DgeY1szT98+EKU8GYnga5WnyatAu+kOQ2VlVX1Mxif6A0Umt0YkSiksCiyGxzx8SPhGe9a53ND1GD4yVDrPA==} + engines: {node: '>=16.20.1'} + + mpath@0.9.0: + resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} + engines: {node: '>=4.0.0'} + + mquery@5.0.0: + resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==} + engines: {node: '>=14.0.0'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + next@15.5.8: + resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-abi@3.85.0: + resolution: {integrity: sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==} + engines: {node: '>=10'} + + node-addon-api@6.1.0: + resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + object-to-formdata@4.5.1: + resolution: {integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==} + + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + payload@3.0.0-beta.135: + resolution: {integrity: sha512-FUvNleHmdpLHrEOtrX1ezyA3RV4BFKyQk4qghELo0hzShusIc9Er1zZEE85rOPeMz7uggfzZL69rfpPDV4anjA==} + engines: {node: ^18.20.2 || >=20.9.0} + hasBin: true + peerDependencies: + graphql: ^16.8.1 + + peek-readable@5.4.2: + resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} + engines: {node: '>=14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-pretty@13.0.0: + resolution: {integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==} + hasBin: true + + pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + + pino@9.5.0: + resolution: {integrity: sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==} + hasBin: true + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + postcss-import@15.1.0: + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true + + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + engines: {node: '>=14'} + hasBin: true + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + process-warning@4.0.1: + resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs-esm@7.0.2: + resolution: {integrity: sha512-D8NAthKSD7SGn748v+GLaaO6k08Mvpoqroa35PqIQC4gtUa8/Pb/k+r0m0NnGBVbHDP1gKZ2nVywqfMisRhV5A==} + engines: {node: '>=18'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-animate-height@2.1.2: + resolution: {integrity: sha512-A9jfz/4CTdsIsE7WCQtO9UkOpMBcBRh8LxyHl2eoZz1ki02jpyUL5xt58gabd0CyeLQ8fRyQ+s2lyV2Ufu8Owg==} + engines: {node: '>= 6.0.0'} + peerDependencies: + react: '>=15.6.2' + react-dom: '>=15.6.2' + + react-datepicker@6.9.0: + resolution: {integrity: sha512-QTxuzeem7BUfVFWv+g5WuvzT0c5BPo+XTCNbMTZKSZQLU+cMMwSUHwspaxuIcDlwNcOH0tiJ+bh1fJ2yxOGYWA==} + peerDependencies: + react: ^16.9.0 || ^17 || ^18 + react-dom: ^16.9.0 || ^17 || ^18 + + react-diff-viewer-continued@3.2.6: + resolution: {integrity: sha512-GrzyqQnjIMoej+jMjWvtVSsQqhXgzEGqpXlJ2dAGfOk7Q26qcm8Gu6xtI430PBUyZsERe8BJSQf+7VZZo8IBNQ==} + engines: {node: '>= 8'} + peerDependencies: + react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + + react-dom@19.2.2: + resolution: {integrity: sha512-fhyD2BLrew6qYf4NNtHff1rLXvzR25rq49p+FeqByOazc6TcSi2n8EYulo5C1PbH+1uBW++5S1SG7FcUU6mlDg==} + peerDependencies: + react: ^19.2.2 + + react-error-boundary@3.1.4: + resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} + engines: {node: '>=10', npm: '>=6'} + peerDependencies: + react: '>=16.13.1' + + react-error-boundary@4.0.13: + resolution: {integrity: sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==} + peerDependencies: + react: '>=16.13.1' + + react-image-crop@10.1.8: + resolution: {integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==} + peerDependencies: + react: '>=16.13.1' + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-onclickoutside@6.13.2: + resolution: {integrity: sha512-h6Hbf1c8b7tIYY4u90mDdBLY4+AGQVMFtIE89HgC0DtVCh/JfKl477gYqUtGLmjZBKK3MJxomP/lFiLbz4sq9A==} + peerDependencies: + react: ^15.5.x || ^16.x || ^17.x || ^18.x + react-dom: ^15.5.x || ^16.x || ^17.x || ^18.x + + react-select@5.8.0: + resolution: {integrity: sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + + react@19.2.2: + resolution: {integrity: sha512-BdOGOY8OKRBcgoDkwqA8Q5XvOIhoNx/Sh6BnGJlet2Abt0X5BK0BDrqGyQgLhAVjD2nAg5f6o01u/OPUhG022Q==} + engines: {node: '>=0.10.0'} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + sanitize-filename@1.6.3: + resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + + sass@1.77.4: + resolution: {integrity: sha512-vcF3Ckow6g939GMA4PeU7b2K/9FALXk2KF9J87txdHzXbUF9XRQRwSxcAs/fGaTnJeBFd7UoV22j3lzMLdM0Pw==} + engines: {node: '>=14.0.0'} + hasBin: true + + scheduler@0.0.0-experimental-3edc000d-20240926: + resolution: {integrity: sha512-360BMNajOhMyrirau0pzWVgeakvrfjbfdqHnX2K+tSGTmn6tBN+6K5NhhaebqeXXWyCU3rl5FApjgF2GN0W5JA==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + scmp@2.1.0: + resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} + + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.32.6: + resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} + engines: {node: '>=14.15.0'} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + sift@17.1.3: + resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + simple-swizzle@0.2.4: + resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} + + simple-wcswidth@1.1.2: + resolution: {integrity: sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + sonic-boom@4.2.0: + resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + + sonner@1.7.4: + resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + streamx@2.23.0: + resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strtok3@8.1.0: + resolution: {integrity: sha512-ExzDvHYPj6F6QkSNe/JxSlBxTh3OrI6wrAIz53ulxo1c4hBJ1bT9C/JrAthEKHWG9riVH3Xzg7B03Oxty6S2Lw==} + engines: {node: '>=16'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + + tailwind-merge@2.6.0: + resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + + tailwindcss@3.4.19: + resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} + engines: {node: '>=14.0.0'} + hasBin: true + + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-fs@3.1.1: + resolution: {integrity: sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + + text-decoder@1.2.3: + resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + token-types@6.1.1: + resolution: {integrity: sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ==} + engines: {node: '>=14.16'} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + truncate-utf8-bytes@1.0.2: + resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + + ts-essentials@10.0.3: + resolution: {integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==} + peerDependencies: + typescript: '>=4.5.0' + peerDependenciesMeta: + typescript: + optional: true + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.19.2: + resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} + engines: {node: '>=18.0.0'} + hasBin: true + + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + update-browserslist-db@1.2.2: + resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + use-context-selector@2.0.0: + resolution: {integrity: sha512-owfuSmUNd3eNp3J9CdDl0kMgfidV+MkDvHPpvthN5ThqM+ibMccNE0k+Iq7TWC6JPFvGZqanqiGCuQx6DyV24g==} + peerDependencies: + react: '>=18.0.0' + scheduler: '>=0.19.0' + + use-isomorphic-layout-effect@1.2.1: + resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + utf8-byte-length@1.0.5: + resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true -packages: - /@alloc/quick-lru@5.2.0: - resolution: - { - integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==, - } - engines: { node: '>=10' } - - /@aws-crypto/ie11-detection@3.0.0: - resolution: - { - integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==, - } - requiresBuild: true - dependencies: - tslib: 1.14.1 - dev: false + xss@1.0.15: + resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==} + engines: {node: '>= 0.10.0'} + hasBin: true + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yjs@13.6.27: + resolution: {integrity: sha512-OIDwaflOaq4wC6YlPBy2L6ceKeKuF7DeTxx+jPzv1FHn9tCZ0ZwSRnUBxD05E3yed46fv/FWJbvR+Ud7x0L7zw==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@apidevtools/json-schema-ref-parser@11.9.3': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/runtime@7.28.4': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@borewit/text-codec@0.1.1': {} + + '@dnd-kit/accessibility@3.1.1(react@19.2.2)': + dependencies: + react: 19.2.2 + tslib: 2.8.1 + + '@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': + dependencies: + '@dnd-kit/accessibility': 3.1.1(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + tslib: 2.8.1 + + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + tslib: 2.8.1 + + '@dnd-kit/utilities@3.2.2(react@19.2.2)': + dependencies: + react: 19.2.2 + tslib: 2.8.1 + + '@emnapi/runtime@1.7.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.27.1 + '@babel/runtime': 7.28.4 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/css@11.13.5': + dependencies: + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + transitivePeerDependencies: + - supports-color + + '@emotion/hash@0.9.2': {} + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.2)': + dependencies: + '@babel/runtime': 7.28.4 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.2) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.2 + optionalDependencies: + '@types/react': 19.2.1 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.2.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.2)': + dependencies: + react: 19.2.2 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + + '@esbuild/aix-ppc64@0.23.1': optional: true - /@aws-crypto/sha256-browser@3.0.0: - resolution: - { - integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==, - } - requiresBuild: true - dependencies: - '@aws-crypto/ie11-detection': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-crypto/supports-web-crypto': 3.0.0 - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-locate-window': 3.535.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - dev: false + '@esbuild/aix-ppc64@0.27.1': optional: true - /@aws-crypto/sha256-js@3.0.0: - resolution: - { - integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==, - } - requiresBuild: true - dependencies: - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.535.0 - tslib: 1.14.1 - dev: false + '@esbuild/android-arm64@0.23.1': optional: true - /@aws-crypto/supports-web-crypto@3.0.0: - resolution: - { - integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==, - } - requiresBuild: true - dependencies: - tslib: 1.14.1 - dev: false + '@esbuild/android-arm64@0.27.1': optional: true - /@aws-crypto/util@3.0.0: - resolution: - { - integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==, - } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - dev: false + '@esbuild/android-arm@0.23.1': optional: true - /@aws-sdk/client-cognito-identity@3.564.0: - resolution: - { - integrity: sha512-AJGd0RXAyycNqb8RBySVkIrzNOd8JzI4sVVC/7pA41t4EeUGM6b2tcsOlt1eVqcNxR1hvn2ZbwnNI8e3OlEnhQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.556.0 - '@aws-sdk/credential-provider-node': 3.564.0 - '@aws-sdk/middleware-host-header': 3.535.0 - '@aws-sdk/middleware-logger': 3.535.0 - '@aws-sdk/middleware-recursion-detection': 3.535.0 - '@aws-sdk/middleware-user-agent': 3.540.0 - '@aws-sdk/region-config-resolver': 3.535.0 - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-endpoints': 3.540.0 - '@aws-sdk/util-user-agent-browser': 3.535.0 - '@aws-sdk/util-user-agent-node': 3.535.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - dev: false + '@esbuild/android-arm@0.27.1': optional: true - /@aws-sdk/client-sso-oidc@3.564.0(@aws-sdk/credential-provider-node@3.564.0): - resolution: - { - integrity: sha512-LWBXiwA0qlGhpJx3fbFQagVEyVPoecGtJh3+5hoc+CTVnT00J7T0jLe3kgemvEI9kjhIyDW+MFkq1jCttrGNJw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - peerDependencies: - '@aws-sdk/credential-provider-node': ^3.564.0 - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.556.0 - '@aws-sdk/credential-provider-node': 3.564.0 - '@aws-sdk/middleware-host-header': 3.535.0 - '@aws-sdk/middleware-logger': 3.535.0 - '@aws-sdk/middleware-recursion-detection': 3.535.0 - '@aws-sdk/middleware-user-agent': 3.540.0 - '@aws-sdk/region-config-resolver': 3.535.0 - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-endpoints': 3.540.0 - '@aws-sdk/util-user-agent-browser': 3.535.0 - '@aws-sdk/util-user-agent-node': 3.535.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - dev: false + '@esbuild/android-x64@0.23.1': optional: true - /@aws-sdk/client-sso@3.556.0: - resolution: - { - integrity: sha512-unXdWS7uvHqCcOyC1de+Fr8m3F2vMg2m24GPea0bg7rVGTYmiyn9mhUX11VCt+ozydrw+F50FQwL6OqoqPocmw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.556.0 - '@aws-sdk/middleware-host-header': 3.535.0 - '@aws-sdk/middleware-logger': 3.535.0 - '@aws-sdk/middleware-recursion-detection': 3.535.0 - '@aws-sdk/middleware-user-agent': 3.540.0 - '@aws-sdk/region-config-resolver': 3.535.0 - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-endpoints': 3.540.0 - '@aws-sdk/util-user-agent-browser': 3.535.0 - '@aws-sdk/util-user-agent-node': 3.535.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - dev: false + '@esbuild/android-x64@0.27.1': optional: true - /@aws-sdk/client-sts@3.556.0(@aws-sdk/credential-provider-node@3.564.0): - resolution: - { - integrity: sha512-TsK3js7Suh9xEmC886aY+bv0KdLLYtzrcmVt6sJ/W6EnDXYQhBuKYFhp03NrN2+vSvMGpqJwR62DyfKe1G0QzQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - peerDependencies: - '@aws-sdk/credential-provider-node': ^3.556.0 - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.556.0 - '@aws-sdk/credential-provider-node': 3.564.0 - '@aws-sdk/middleware-host-header': 3.535.0 - '@aws-sdk/middleware-logger': 3.535.0 - '@aws-sdk/middleware-recursion-detection': 3.535.0 - '@aws-sdk/middleware-user-agent': 3.540.0 - '@aws-sdk/region-config-resolver': 3.535.0 - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-endpoints': 3.540.0 - '@aws-sdk/util-user-agent-browser': 3.535.0 - '@aws-sdk/util-user-agent-node': 3.535.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - dev: false + '@esbuild/darwin-arm64@0.23.1': optional: true - /@aws-sdk/core@3.556.0: - resolution: - { - integrity: sha512-vJaSaHw2kPQlo11j/Rzuz0gk1tEaKdz+2ser0f0qZ5vwFlANjt08m/frU17ctnVKC1s58bxpctO/1P894fHLrA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/core': 1.4.2 - '@smithy/protocol-http': 3.3.0 - '@smithy/signature-v4': 2.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - fast-xml-parser: 4.2.5 - tslib: 2.6.2 - dev: false + '@esbuild/darwin-arm64@0.27.1': optional: true - /@aws-sdk/credential-provider-cognito-identity@3.564.0: - resolution: - { - integrity: sha512-rjpj+VR9NbF9hg2H0gfuhbQL+6WlRVEBBxI8rweSsSm5r5exENqP+xmEdL6mmFCyM/EjDQswNs0td2tVSc/onw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/client-cognito-identity': 3.564.0 - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - dev: false + '@esbuild/darwin-x64@0.23.1': optional: true - /@aws-sdk/credential-provider-env@3.535.0: - resolution: - { - integrity: sha512-XppwO8c0GCGSAvdzyJOhbtktSEaShg14VJKg8mpMa1XcgqzmcqqHQjtDWbx5rZheY1VdpXZhpEzJkB6LpQejpA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false + '@esbuild/darwin-x64@0.27.1': optional: true - /@aws-sdk/credential-provider-http@3.552.0: - resolution: - { - integrity: sha512-vsmu7Cz1i45pFEqzVb4JcFmAmVnWFNLsGheZc8SCptlqCO5voETrZZILHYIl4cjKkSDk3pblBOf0PhyjqWW6WQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/property-provider': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 - dev: false + '@esbuild/freebsd-arm64@0.23.1': optional: true - /@aws-sdk/credential-provider-ini@3.564.0(@aws-sdk/credential-provider-node@3.564.0): - resolution: - { - integrity: sha512-kiEfBoKRcbX7I/rjhVGJrTUQ0895ANhPu6KE1GRZW7wc1gIGgKGJ+0tvAqRtQjYX0U9pivEDb0dh16OF9PBFFw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/client-sts': 3.556.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/credential-provider-env': 3.535.0 - '@aws-sdk/credential-provider-process': 3.535.0 - '@aws-sdk/credential-provider-sso': 3.564.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/credential-provider-web-identity': 3.556.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/types': 3.535.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/credential-provider-node' - - aws-crt - dev: false + '@esbuild/freebsd-arm64@0.27.1': optional: true - /@aws-sdk/credential-provider-node@3.564.0: - resolution: - { - integrity: sha512-HXD5ZCXzfcd6cJ/pW8frh8DuYlKaCd/JKmwzuCRUxgxZwbLEeNmyRYvF+D7osETJJZ4VIwgVbpEw1yLqRz1onw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/credential-provider-env': 3.535.0 - '@aws-sdk/credential-provider-http': 3.552.0 - '@aws-sdk/credential-provider-ini': 3.564.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/credential-provider-process': 3.535.0 - '@aws-sdk/credential-provider-sso': 3.564.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/credential-provider-web-identity': 3.556.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/types': 3.535.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - dev: false + '@esbuild/freebsd-x64@0.23.1': optional: true - /@aws-sdk/credential-provider-process@3.535.0: - resolution: - { - integrity: sha512-9O1OaprGCnlb/kYl8RwmH7Mlg8JREZctB8r9sa1KhSsWFq/SWO0AuJTyowxD7zL5PkeS4eTvzFFHWCa3OO5epA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false + '@esbuild/freebsd-x64@0.27.1': optional: true - /@aws-sdk/credential-provider-sso@3.564.0(@aws-sdk/credential-provider-node@3.564.0): - resolution: - { - integrity: sha512-Wv0NV8tDwtydEpsp/kVZ22Z+40bsSBDYgYZ1Uxx+KR8a1PvT6B5FnEtccWTJ371sQG/uqLum7dXSbJq1Qqze1w==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/client-sso': 3.556.0 - '@aws-sdk/token-providers': 3.564.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/credential-provider-node' - - aws-crt - dev: false + '@esbuild/linux-arm64@0.23.1': optional: true - /@aws-sdk/credential-provider-web-identity@3.556.0(@aws-sdk/credential-provider-node@3.564.0): - resolution: - { - integrity: sha512-R/YAL8Uh8i+dzVjzMnbcWLIGeeRi2mioHVGnVF+minmaIkCiQMZg2HPrdlKm49El+RljT28Nl5YHRuiqzEIwMA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/client-sts': 3.556.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/credential-provider-node' - - aws-crt - dev: false + '@esbuild/linux-arm64@0.27.1': optional: true - /@aws-sdk/credential-providers@3.564.0: - resolution: - { - integrity: sha512-QQrVTPuRRK37IEtCqzGpStfvr5fZMqxlCQFNJ6mDpHOkL1oyrYIrBpWCB4N95dJyoyLsogleDoFZelfjM9HIzQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/client-cognito-identity': 3.564.0 - '@aws-sdk/client-sso': 3.556.0 - '@aws-sdk/client-sts': 3.556.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/credential-provider-cognito-identity': 3.564.0 - '@aws-sdk/credential-provider-env': 3.535.0 - '@aws-sdk/credential-provider-http': 3.552.0 - '@aws-sdk/credential-provider-ini': 3.564.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/credential-provider-node': 3.564.0 - '@aws-sdk/credential-provider-process': 3.535.0 - '@aws-sdk/credential-provider-sso': 3.564.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/credential-provider-web-identity': 3.556.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/types': 3.535.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - dev: false + '@esbuild/linux-arm@0.23.1': optional: true - /@aws-sdk/middleware-host-header@3.535.0: - resolution: - { - integrity: sha512-0h6TWjBWtDaYwHMQJI9ulafeS4lLaw1vIxRjbpH0svFRt6Eve+Sy8NlVhECfTU2hNz/fLubvrUxsXoThaLBIew==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false + '@esbuild/linux-arm@0.27.1': optional: true - /@aws-sdk/middleware-logger@3.535.0: - resolution: - { - integrity: sha512-huNHpONOrEDrdRTvSQr1cJiRMNf0S52NDXtaPzdxiubTkP+vni2MohmZANMOai/qT0olmEVX01LhZ0ZAOgmg6A==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false + '@esbuild/linux-ia32@0.23.1': optional: true - /@aws-sdk/middleware-recursion-detection@3.535.0: - resolution: - { - integrity: sha512-am2qgGs+gwqmR4wHLWpzlZ8PWhm4ktj5bYSgDrsOfjhdBlWNxvPoID9/pDAz5RWL48+oH7I6SQzMqxXsFDikrw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false + '@esbuild/linux-ia32@0.27.1': optional: true - /@aws-sdk/middleware-user-agent@3.540.0: - resolution: - { - integrity: sha512-8Rd6wPeXDnOYzWj1XCmOKcx/Q87L0K1/EHqOBocGjLVbN3gmRxBvpmR1pRTjf7IsWfnnzN5btqtcAkfDPYQUMQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@aws-sdk/util-endpoints': 3.540.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false + '@esbuild/linux-loong64@0.23.1': optional: true - /@aws-sdk/region-config-resolver@3.535.0: - resolution: - { - integrity: sha512-IXOznDiaItBjsQy4Fil0kzX/J3HxIOknEphqHbOfUf+LpA5ugcsxuQQONrbEQusCBnfJyymrldBvBhFmtlU9Wg==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-config-provider': 2.3.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - dev: false + '@esbuild/linux-loong64@0.27.1': optional: true - /@aws-sdk/token-providers@3.564.0(@aws-sdk/credential-provider-node@3.564.0): - resolution: - { - integrity: sha512-Kk5ixcl9HjqwzfBJZGQAtsqwKa7Z8P7Mdug837BG8zCJbhf7wwNsmItzXTiAlpVrDZyT8P1yWIxsLOS1YUtmow==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/client-sso-oidc': 3.564.0(@aws-sdk/credential-provider-node@3.564.0) - '@aws-sdk/types': 3.535.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/credential-provider-node' - - aws-crt - dev: false + '@esbuild/linux-mips64el@0.23.1': optional: true - /@aws-sdk/types@3.535.0: - resolution: - { - integrity: sha512-aY4MYfduNj+sRR37U7XxYR8wemfbKP6lx00ze2M2uubn7mZotuVrWYAafbMSXrdEMSToE5JDhr28vArSOoLcSg==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false + '@esbuild/linux-mips64el@0.27.1': optional: true - /@aws-sdk/util-endpoints@3.540.0: - resolution: - { - integrity: sha512-1kMyQFAWx6f8alaI6UT65/5YW/7pDWAKAdNwL6vuJLea03KrZRX3PMoONOSJpAS5m3Ot7HlWZvf3wZDNTLELZw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/types': 2.12.0 - '@smithy/util-endpoints': 1.2.0 - tslib: 2.6.2 - dev: false + '@esbuild/linux-ppc64@0.23.1': optional: true - /@aws-sdk/util-locate-window@3.535.0: - resolution: - { - integrity: sha512-PHJ3SL6d2jpcgbqdgiPxkXpu7Drc2PYViwxSIqvvMKhDwzSB1W3mMvtpzwKM4IE7zLFodZo0GKjJ9AsoXndXhA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - tslib: 2.6.2 - dev: false + '@esbuild/linux-ppc64@0.27.1': optional: true - /@aws-sdk/util-user-agent-browser@3.535.0: - resolution: - { - integrity: sha512-RWMcF/xV5n+nhaA/Ff5P3yNP3Kur/I+VNZngog4TEs92oB/nwOdAg/2JL8bVAhUbMrjTjpwm7PItziYFQoqyig==, - } - requiresBuild: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/types': 2.12.0 - bowser: 2.11.0 - tslib: 2.6.2 - dev: false + '@esbuild/linux-riscv64@0.23.1': optional: true - /@aws-sdk/util-user-agent-node@3.535.0: - resolution: - { - integrity: sha512-dRek0zUuIT25wOWJlsRm97nTkUlh1NDcLsQZIN2Y8KxhwoXXWtJs5vaDPT+qAg+OpcNj80i1zLR/CirqlFg/TQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - peerDependencies: - aws-crt: '>=1.0.0' - peerDependenciesMeta: - aws-crt: - optional: true - dependencies: - '@aws-sdk/types': 3.535.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false + '@esbuild/linux-riscv64@0.27.1': optional: true - /@aws-sdk/util-utf8-browser@3.259.0: - resolution: - { - integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==, - } - requiresBuild: true - dependencies: - tslib: 2.6.2 - dev: false + '@esbuild/linux-s390x@0.23.1': optional: true - /@babel/code-frame@7.24.2: - resolution: - { - integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==, - } - engines: { node: '>=6.9.0' } - dependencies: - '@babel/highlight': 7.24.2 - picocolors: 1.0.0 - dev: false - - /@babel/helper-module-imports@7.24.3: - resolution: - { - integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==, - } - engines: { node: '>=6.9.0' } - dependencies: - '@babel/types': 7.24.0 - dev: false - - /@babel/helper-string-parser@7.24.1: - resolution: - { - integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==, - } - engines: { node: '>=6.9.0' } - dev: false - - /@babel/helper-validator-identifier@7.22.20: - resolution: - { - integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==, - } - engines: { node: '>=6.9.0' } - dev: false - - /@babel/highlight@7.24.2: - resolution: - { - integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==, - } - engines: { node: '>=6.9.0' } - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.0.0 - dev: false - - /@babel/runtime@7.24.4: - resolution: - { - integrity: sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==, - } - engines: { node: '>=6.9.0' } - dependencies: - regenerator-runtime: 0.14.1 - dev: false - - /@babel/types@7.24.0: - resolution: - { - integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==, - } - engines: { node: '>=6.9.0' } - dependencies: - '@babel/helper-string-parser': 7.24.1 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 - dev: false - - /@bcherny/json-schema-ref-parser@9.0.9: - resolution: - { - integrity: sha512-vmEmnJCfpkLdas++9OYg6riIezTYqTHpqUTODJzHLzs5UnXujbOJW9VwcVCnyo1mVRt32FRr23iXBx/sX8YbeQ==, - } + '@esbuild/linux-s390x@0.27.1': + optional: true + + '@esbuild/linux-x64@0.23.1': + optional: true + + '@esbuild/linux-x64@0.27.1': + optional: true + + '@esbuild/netbsd-arm64@0.27.1': + optional: true + + '@esbuild/netbsd-x64@0.23.1': + optional: true + + '@esbuild/netbsd-x64@0.27.1': + optional: true + + '@esbuild/openbsd-arm64@0.23.1': + optional: true + + '@esbuild/openbsd-arm64@0.27.1': + optional: true + + '@esbuild/openbsd-x64@0.23.1': + optional: true + + '@esbuild/openbsd-x64@0.27.1': + optional: true + + '@esbuild/openharmony-arm64@0.27.1': + optional: true + + '@esbuild/sunos-x64@0.23.1': + optional: true + + '@esbuild/sunos-x64@0.27.1': + optional: true + + '@esbuild/win32-arm64@0.23.1': + optional: true + + '@esbuild/win32-arm64@0.27.1': + optional: true + + '@esbuild/win32-ia32@0.23.1': + optional: true + + '@esbuild/win32-ia32@0.27.1': + optional: true + + '@esbuild/win32-x64@0.23.1': + optional: true + + '@esbuild/win32-x64@0.27.1': + optional: true + + '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@jsdevtools/ono': 7.1.3 - '@types/json-schema': 7.0.15 - call-me-maybe: 1.0.2 - js-yaml: 4.1.0 - dev: false - - /@dnd-kit/accessibility@3.1.0(react@18.3.1): - resolution: - { - integrity: sha512-ea7IkhKvlJUv9iSHJOnxinBcoOI3ppGnnL+VDJ75O45Nss6HtZd8IdN8touXPDtASfeI2T2LImb8VOZcL47wjQ==, - } - peerDependencies: - react: '>=16.8.0' + body-scroll-lock: 4.0.0-beta.0 + focus-trap: 7.5.4 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + + '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 18.3.1 - tslib: 2.6.2 - dev: false + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - /@dnd-kit/core@6.0.8(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==, - } - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' + '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/accessibility': 3.1.0(react@18.3.1) - '@dnd-kit/utilities': 3.2.2(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - tslib: 2.6.2 - dev: false - - /@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8)(react@18.3.1): - resolution: - { - integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==, - } - peerDependencies: - '@dnd-kit/core': ^6.0.7 - react: '>=16.8.0' + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@floating-ui/core@1.7.3': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@18.3.1)(react@18.3.1) - '@dnd-kit/utilities': 3.2.2(react@18.3.1) - react: 18.3.1 - tslib: 2.6.2 - dev: false - - /@dnd-kit/utilities@3.2.2(react@18.3.1): - resolution: - { - integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==, - } - peerDependencies: - react: '>=16.8.0' + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': dependencies: - react: 18.3.1 - tslib: 2.6.2 - dev: false - - /@emotion/babel-plugin@11.11.0: - resolution: - { - integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==, - } - dependencies: - '@babel/helper-module-imports': 7.24.3 - '@babel/runtime': 7.24.4 - '@emotion/hash': 0.9.1 - '@emotion/memoize': 0.8.1 - '@emotion/serialize': 1.1.4 - babel-plugin-macros: 3.1.0 - convert-source-map: 1.9.0 - escape-string-regexp: 4.0.0 - find-root: 1.1.0 - source-map: 0.5.7 - stylis: 4.2.0 - dev: false - - /@emotion/cache@11.11.0: - resolution: - { - integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==, - } - dependencies: - '@emotion/memoize': 0.8.1 - '@emotion/sheet': 1.2.2 - '@emotion/utils': 1.2.1 - '@emotion/weak-memoize': 0.3.1 - stylis: 4.2.0 - dev: false - - /@emotion/css@11.11.2: - resolution: - { - integrity: sha512-VJxe1ucoMYMS7DkiMdC2T7PWNbrEI0a39YRiyDvK2qq4lXwjRbVP/z4lpG+odCsRzadlR+1ywwrTzhdm5HNdew==, - } - dependencies: - '@emotion/babel-plugin': 11.11.0 - '@emotion/cache': 11.11.0 - '@emotion/serialize': 1.1.4 - '@emotion/sheet': 1.2.2 - '@emotion/utils': 1.2.1 - dev: false - - /@emotion/hash@0.9.1: - resolution: - { - integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==, - } - dev: false - - /@emotion/memoize@0.8.1: - resolution: - { - integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==, - } - dev: false - - /@emotion/react@11.11.4(@types/react@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==, - } - peerDependencies: - '@types/react': '*' - react: '>=16.8.0' - peerDependenciesMeta: - '@types/react': - optional: true + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@babel/runtime': 7.24.4 - '@emotion/babel-plugin': 11.11.0 - '@emotion/cache': 11.11.0 - '@emotion/serialize': 1.1.4 - '@emotion/use-insertion-effect-with-fallbacks': 1.0.1(react@18.3.1) - '@emotion/utils': 1.2.1 - '@emotion/weak-memoize': 0.3.1 - '@types/react': 18.3.1 - hoist-non-react-statics: 3.3.2 - react: 18.3.1 - dev: false - - /@emotion/serialize@1.1.4: - resolution: - { - integrity: sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==, - } - dependencies: - '@emotion/hash': 0.9.1 - '@emotion/memoize': 0.8.1 - '@emotion/unitless': 0.8.1 - '@emotion/utils': 1.2.1 - csstype: 3.1.3 - dev: false - - /@emotion/sheet@1.2.2: - resolution: - { - integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==, - } - dev: false - - /@emotion/unitless@0.8.1: - resolution: - { - integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==, - } - dev: false - - /@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.3.1): - resolution: - { - integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==, - } - peerDependencies: - react: '>=16.8.0' + '@floating-ui/dom': 1.7.4 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + '@floating-ui/react@0.26.28(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 18.3.1 - dev: false - - /@emotion/utils@1.2.1: - resolution: - { - integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==, - } - dev: false - - /@emotion/weak-memoize@0.3.1: - resolution: - { - integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==, - } - dev: false - - /@esbuild/aix-ppc64@0.19.12: - resolution: - { - integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==, - } - engines: { node: '>=12' } - cpu: [ppc64] - os: [aix] - requiresBuild: true - dev: true + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@floating-ui/utils': 0.2.10 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + tabbable: 6.3.0 + + '@floating-ui/utils@0.2.10': {} + + '@img/colour@1.0.0': optional: true - /@esbuild/android-arm64@0.19.12: - resolution: - { - integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==, - } - engines: { node: '>=12' } - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - /@esbuild/android-arm@0.19.12: - resolution: - { - integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==, - } - engines: { node: '>=12' } - cpu: [arm] - os: [android] - requiresBuild: true - dev: true + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 optional: true - /@esbuild/android-x64@0.19.12: - resolution: - { - integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==, - } - engines: { node: '>=12' } - cpu: [x64] - os: [android] - requiresBuild: true - dev: true + '@img/sharp-libvips-darwin-arm64@1.2.4': optional: true - /@esbuild/darwin-arm64@0.19.12: - resolution: - { - integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==, - } - engines: { node: '>=12' } - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true + '@img/sharp-libvips-darwin-x64@1.2.4': optional: true - /@esbuild/darwin-x64@0.19.12: - resolution: - { - integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==, - } - engines: { node: '>=12' } - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true + '@img/sharp-libvips-linux-arm64@1.2.4': optional: true - /@esbuild/freebsd-arm64@0.19.12: - resolution: - { - integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==, - } - engines: { node: '>=12' } - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - /@esbuild/freebsd-x64@0.19.12: - resolution: - { - integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==, - } - engines: { node: '>=12' } - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - /@esbuild/linux-arm64@0.19.12: - resolution: - { - integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==, - } - engines: { node: '>=12' } - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - /@esbuild/linux-arm@0.19.12: - resolution: - { - integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==, - } - engines: { node: '>=12' } - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - /@esbuild/linux-ia32@0.19.12: - resolution: - { - integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==, - } - engines: { node: '>=12' } - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - /@esbuild/linux-loong64@0.19.12: - resolution: - { - integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==, - } - engines: { node: '>=12' } - cpu: [loong64] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - /@esbuild/linux-mips64el@0.19.12: - resolution: - { - integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==, - } - engines: { node: '>=12' } - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-libvips-linuxmusl-x64@1.2.4': optional: true - /@esbuild/linux-ppc64@0.19.12: - resolution: - { - integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==, - } - engines: { node: '>=12' } - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - /@esbuild/linux-riscv64@0.19.12: - resolution: - { - integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==, - } - engines: { node: '>=12' } - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - /@esbuild/linux-s390x@0.19.12: - resolution: - { - integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==, - } - engines: { node: '>=12' } - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - /@esbuild/linux-x64@0.19.12: - resolution: - { - integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==, - } - engines: { node: '>=12' } - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - /@esbuild/netbsd-x64@0.19.12: - resolution: - { - integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==, - } - engines: { node: '>=12' } - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - /@esbuild/openbsd-x64@0.19.12: - resolution: - { - integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==, - } - engines: { node: '>=12' } - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - /@esbuild/sunos-x64@0.19.12: - resolution: - { - integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==, - } - engines: { node: '>=12' } - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - /@esbuild/win32-arm64@0.19.12: - resolution: - { - integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==, - } - engines: { node: '>=12' } - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true - /@esbuild/win32-ia32@0.19.12: - resolution: - { - integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==, - } - engines: { node: '>=12' } - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.7.1 optional: true - /@esbuild/win32-x64@0.19.12: - resolution: - { - integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==, - } - engines: { node: '>=12' } - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true + '@img/sharp-win32-arm64@0.34.5': optional: true - /@faceless-ui/modal@2.0.2(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-CtwUn+hHEaoYUjREzQKGRbEp55VzUx7sC+hxIxmCPwg7Yd5KXkQzSfoUfRAHqT/1MFfE1B2QCHVVbhtSnFL9BA==, - } - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': dependencies: - body-scroll-lock: 3.1.5 - focus-trap: 6.9.4 - qs: 6.12.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-transition-group: 4.4.5(react-dom@18.3.1)(react@18.3.1) - dev: false - - /@faceless-ui/scroll-info@1.3.0(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-X+doJMzQqyVGpwV/YgXUAalNWepP2W8ThgZspKZLFG43zTYLVTU17BYCjjY+ggKuA3b0W3JyXZ2M8f247AdmHw==, - } - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - /@faceless-ui/window-info@2.1.2(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-IvZM6mLWFRin904180115Y6BgsvAN9M5uCMJEHhiQgTgzDMiYVtUww7GlWRsvemubMRF6c9Q+j79qW7uPPuMBg==, - } - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@jsdevtools/ono@7.1.3': {} + + '@lexical/clipboard@0.20.0': dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@floating-ui/core@1.6.1: - resolution: - { - integrity: sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==, - } - dependencies: - '@floating-ui/utils': 0.2.2 - dev: false - - /@floating-ui/dom@1.6.4: - resolution: - { - integrity: sha512-0G8R+zOvQsAG1pg2Q99P21jiqxqGBW1iRe/iXHsBRBxnpXKFI8QwbB4x5KmYLggNO5m34IQgOIu9SCRfR/WWiQ==, - } - dependencies: - '@floating-ui/core': 1.6.1 - '@floating-ui/utils': 0.2.2 - dev: false - - /@floating-ui/react-dom@2.0.9(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-q0umO0+LQK4+p6aGyvzASqKbKOJcAHJ7ycE9CuUvfx3s9zTHWmGJTPOIlM/hmSBfUfg/XfY5YhLBLR/LHwShQQ==, - } - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' + '@lexical/html': 0.20.0 + '@lexical/list': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/code@0.20.0': + dependencies: + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + prismjs: 1.30.0 + + '@lexical/devtools-core@0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@floating-ui/dom': 1.6.4 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false + '@lexical/html': 0.20.0 + '@lexical/link': 0.20.0 + '@lexical/mark': 0.20.0 + '@lexical/table': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - /@floating-ui/react@0.26.13(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-kBa9wntpugzrZ8t/4yWelvSmEKZdeTXTJzrxqyrLmcU/n1SM4nvse8yQh2e1b37rJGvtu0EplV9+IkBrCJ1vkw==, - } - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' + '@lexical/dragon@0.20.0': dependencies: - '@floating-ui/react-dom': 2.0.9(react-dom@18.3.1)(react@18.3.1) - '@floating-ui/utils': 0.2.2 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - tabbable: 6.2.0 - dev: false - - /@floating-ui/utils@0.2.2: - resolution: - { - integrity: sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==, - } - dev: false - - /@hapi/hoek@9.3.0: - resolution: - { - integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==, - } - dev: false - - /@hapi/topo@5.1.0: - resolution: - { - integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==, - } - dependencies: - '@hapi/hoek': 9.3.0 - dev: false - - /@isaacs/cliui@8.0.2: - resolution: - { - integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, - } - engines: { node: '>=12' } - dependencies: - string-width: 5.1.2 - string-width-cjs: /string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: /strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: /wrap-ansi@7.0.0 - - /@jridgewell/gen-mapping@0.3.5: - resolution: - { - integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==, - } - engines: { node: '>=6.0.0' } - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.25 - - /@jridgewell/resolve-uri@3.1.2: - resolution: - { - integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, - } - engines: { node: '>=6.0.0' } - - /@jridgewell/set-array@1.2.1: - resolution: - { - integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==, - } - engines: { node: '>=6.0.0' } - - /@jridgewell/sourcemap-codec@1.4.15: - resolution: - { - integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==, - } - - /@jridgewell/trace-mapping@0.3.25: - resolution: - { - integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==, - } + lexical: 0.20.0 + + '@lexical/hashtag@0.20.0': dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - - /@jsdevtools/ono@7.1.3: - resolution: - { - integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==, - } - dev: false - - /@lexical/clipboard@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-gMSbVeqb7S+XAi/EMMlwl+FCurLPugN2jAXcp5k5ZaUd7be8B+iupbYdoKkjt4qBhxmvmfe9k46GoC0QOPl/nw==, - } - peerDependencies: - lexical: 0.13.1 - dependencies: - '@lexical/html': 0.13.1(lexical@0.13.1) - '@lexical/list': 0.13.1(lexical@0.13.1) - '@lexical/selection': 0.13.1(lexical@0.13.1) - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false - - /@lexical/code@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-QK77r3QgEtJy96ahYXNgpve8EY64BQgBSnPDOuqVrLdl92nPzjqzlsko2OZldlrt7gjXcfl9nqfhZ/CAhStfOg==, - } - peerDependencies: - lexical: 0.13.1 - dependencies: - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - prismjs: 1.29.0 - dev: false - - /@lexical/dragon@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-aNlqfif4//jW7gOxbBgdrbDovU6m3EwQrUw+Y/vqRkY+sWmloyAUeNwCPH1QP3Q5cvfolzOeN5igfBljsFr+1g==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/headless@0.20.0': dependencies: - lexical: 0.13.1 - dev: false + lexical: 0.20.0 - /@lexical/hashtag@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-Dl0dUG4ZXNjYYuAUR0GMGpLGsA+cps2/ln3xEmy28bZR0sKkjXugsu2QOIxZjYIPBewDrXzPcvK8md45cMYoSg==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/history@0.20.0': dependencies: - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false + '@lexical/utils': 0.20.0 + lexical: 0.20.0 - /@lexical/headless@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-W2mLUuWPrsyf2n73NWM8nKiBI11lEpVVzKE0OzMsjTskv5+AAMaeu1wQ7M1508vKdCcUZwA6AOh3To/hstLEpw==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/html@0.20.0': dependencies: - lexical: 0.13.1 - dev: false + '@lexical/selection': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 - /@lexical/history@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-cZXt30MalEEiRaflE9tHeGYnwT1xSDjXLsf9M409DSU9POJyZ1fsULJrG1tWv2uFQOhwal33rve9+MatUlITrg==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/link@0.20.0': dependencies: - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false + '@lexical/utils': 0.20.0 + lexical: 0.20.0 - /@lexical/html@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-XkZrnCSHIUavtpMol6aG8YsJ5KqC9hMxEhAENf3HTGi3ocysCByyXOyt1EhEYpjJvgDG4wRqt25xGDbLjj1/sA==, - } - peerDependencies: - lexical: 0.13.1 - dependencies: - '@lexical/selection': 0.13.1(lexical@0.13.1) - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false - - /@lexical/link@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-7E3B2juL2UoMj2n+CiyFZ7tlpsdViAoIE7MpegXwfe/VQ66wFwk/VxGTa/69ng2EoF7E0kh+SldvGQDrWAWb1g==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/list@0.20.0': dependencies: - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false + '@lexical/utils': 0.20.0 + lexical: 0.20.0 - /@lexical/list@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-6U1pmNZcKLuOWiWRML8Raf9zSEuUCMlsOye82niyF6I0rpPgYo5UFghAAbGISDsyqzM1B2L4BgJ6XrCk/dJptg==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/mark@0.20.0': dependencies: - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false + '@lexical/utils': 0.20.0 + lexical: 0.20.0 - /@lexical/mark@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-dW27PW8wWDOKFqXTBUuUfV+umU0KfwvXGkPUAxRJrvwUWk5RKaS48LhgbNlQ5BfT84Q8dSiQzvbaa6T40t9a3A==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/markdown@0.20.0': dependencies: - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false + '@lexical/code': 0.20.0 + '@lexical/link': 0.20.0 + '@lexical/list': 0.20.0 + '@lexical/rich-text': 0.20.0 + '@lexical/text': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 - /@lexical/markdown@0.13.1(@lexical/clipboard@0.13.1)(@lexical/selection@0.13.1)(lexical@0.13.1): - resolution: - { - integrity: sha512-6tbdme2h5Zy/M88loVQVH5G0Nt7VMR9UUkyiSaicyBRDOU2OHacaXEp+KSS/XuF+d7TA+v/SzyDq8HS77cO1wA==, - } - peerDependencies: - lexical: 0.13.1 - dependencies: - '@lexical/code': 0.13.1(lexical@0.13.1) - '@lexical/link': 0.13.1(lexical@0.13.1) - '@lexical/list': 0.13.1(lexical@0.13.1) - '@lexical/rich-text': 0.13.1(@lexical/clipboard@0.13.1)(@lexical/selection@0.13.1)(@lexical/utils@0.13.1)(lexical@0.13.1) - '@lexical/text': 0.13.1(lexical@0.13.1) - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - transitivePeerDependencies: - - '@lexical/clipboard' - - '@lexical/selection' - dev: false - - /@lexical/offset@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-j/RZcztJ7dyTrfA2+C3yXDzWDXV+XmMpD5BYeQCEApaHvlo20PHt1BISk7RcrnQW8PdzGvpKblRWf//c08LS9w==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/offset@0.20.0': dependencies: - lexical: 0.13.1 - dev: false + lexical: 0.20.0 - /@lexical/overflow@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-Uw34j+qG2UJRCIR+bykfFMduFk7Pc4r/kNt8N1rjxGuGXAsreTVch1iOhu7Ev6tJgkURsduKuaJCAi7iHnKl7g==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/overflow@0.20.0': dependencies: - lexical: 0.13.1 - dev: false + lexical: 0.20.0 - /@lexical/plain-text@0.13.1(@lexical/clipboard@0.13.1)(@lexical/selection@0.13.1)(@lexical/utils@0.13.1)(lexical@0.13.1): - resolution: - { - integrity: sha512-4j5KAsMKUvJ8LhVDSS4zczbYXzdfmgYSAVhmqpSnJtud425Nk0TAfpUBLFoivxZB7KMoT1LGWQZvd47IvJPvtA==, - } - peerDependencies: - '@lexical/clipboard': 0.13.1 - '@lexical/selection': 0.13.1 - '@lexical/utils': 0.13.1 - lexical: 0.13.1 - dependencies: - '@lexical/clipboard': 0.13.1(lexical@0.13.1) - '@lexical/selection': 0.13.1(lexical@0.13.1) - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false - - /@lexical/react@0.13.1(lexical@0.13.1)(react-dom@18.3.1)(react@18.3.1)(yjs@13.6.15): - resolution: - { - integrity: sha512-Sy6EL230KAb0RZsZf1dZrRrc3+rvCDQWltcd8C/cqBUYlxsLYCW9s4f3RB2werngD/PtLYbBB48SYXNkIALITA==, - } - peerDependencies: - lexical: 0.13.1 - react: '>=17.x' - react-dom: '>=17.x' + '@lexical/plain-text@0.20.0': dependencies: - '@lexical/clipboard': 0.13.1(lexical@0.13.1) - '@lexical/code': 0.13.1(lexical@0.13.1) - '@lexical/dragon': 0.13.1(lexical@0.13.1) - '@lexical/hashtag': 0.13.1(lexical@0.13.1) - '@lexical/history': 0.13.1(lexical@0.13.1) - '@lexical/link': 0.13.1(lexical@0.13.1) - '@lexical/list': 0.13.1(lexical@0.13.1) - '@lexical/mark': 0.13.1(lexical@0.13.1) - '@lexical/markdown': 0.13.1(@lexical/clipboard@0.13.1)(@lexical/selection@0.13.1)(lexical@0.13.1) - '@lexical/overflow': 0.13.1(lexical@0.13.1) - '@lexical/plain-text': 0.13.1(@lexical/clipboard@0.13.1)(@lexical/selection@0.13.1)(@lexical/utils@0.13.1)(lexical@0.13.1) - '@lexical/rich-text': 0.13.1(@lexical/clipboard@0.13.1)(@lexical/selection@0.13.1)(@lexical/utils@0.13.1)(lexical@0.13.1) - '@lexical/selection': 0.13.1(lexical@0.13.1) - '@lexical/table': 0.13.1(lexical@0.13.1) - '@lexical/text': 0.13.1(lexical@0.13.1) - '@lexical/utils': 0.13.1(lexical@0.13.1) - '@lexical/yjs': 0.13.1(lexical@0.13.1)(yjs@13.6.15) - lexical: 0.13.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-error-boundary: 3.1.4(react@18.3.1) + '@lexical/clipboard': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 + + '@lexical/react@0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.27)': + dependencies: + '@lexical/clipboard': 0.20.0 + '@lexical/code': 0.20.0 + '@lexical/devtools-core': 0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@lexical/dragon': 0.20.0 + '@lexical/hashtag': 0.20.0 + '@lexical/history': 0.20.0 + '@lexical/link': 0.20.0 + '@lexical/list': 0.20.0 + '@lexical/mark': 0.20.0 + '@lexical/markdown': 0.20.0 + '@lexical/overflow': 0.20.0 + '@lexical/plain-text': 0.20.0 + '@lexical/rich-text': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/table': 0.20.0 + '@lexical/text': 0.20.0 + '@lexical/utils': 0.20.0 + '@lexical/yjs': 0.20.0(yjs@13.6.27) + lexical: 0.20.0 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 3.1.4(react@19.2.2) transitivePeerDependencies: - yjs - dev: false - /@lexical/rich-text@0.13.1(@lexical/clipboard@0.13.1)(@lexical/selection@0.13.1)(@lexical/utils@0.13.1)(lexical@0.13.1): - resolution: - { - integrity: sha512-HliB9Ync06mv9DBg/5j0lIsTJp+exLHlaLJe+n8Zq1QNTzZzu2LsIT/Crquk50In7K/cjtlaQ/d5RB0LkjMHYg==, - } - peerDependencies: - '@lexical/clipboard': 0.13.1 - '@lexical/selection': 0.13.1 - '@lexical/utils': 0.13.1 - lexical: 0.13.1 - dependencies: - '@lexical/clipboard': 0.13.1(lexical@0.13.1) - '@lexical/selection': 0.13.1(lexical@0.13.1) - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false - - /@lexical/selection@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-Kt9eSwjxPznj7yzIYipu9yYEgmRJhHiq3DNxHRxInYcZJWWNNHum2xKyxwwcN8QYBBzgfPegfM/geqQEJSV1lQ==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/rich-text@0.20.0': dependencies: - lexical: 0.13.1 - dev: false + '@lexical/clipboard': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 - /@lexical/table@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-VQzgkfkEmnvn6C64O/kvl0HI3bFoBh3WA/U67ALw+DS11Mb5CKjbt0Gzm/258/reIxNMpshjjicpWMv9Miwauw==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/selection@0.20.0': dependencies: - '@lexical/utils': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false + lexical: 0.20.0 - /@lexical/text@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-NYy3TZKt3qzReDwN2Rr5RxyFlg84JjXP2JQGMrXSSN7wYe73ysQIU6PqdVrz4iZkP+w34F3pl55dJ24ei3An9w==, - } - peerDependencies: - lexical: 0.13.1 + '@lexical/table@0.20.0': dependencies: - lexical: 0.13.1 - dev: false + '@lexical/clipboard': 0.20.0 + '@lexical/utils': 0.20.0 + lexical: 0.20.0 - /@lexical/utils@0.13.1(lexical@0.13.1): - resolution: - { - integrity: sha512-AtQQKzYymkbOaQxaBXjRBS8IPxF9zWQnqwHTUTrJqJ4hX71aIQd/thqZbfQETAFJfC8pNBZw5zpxN6yPHk23dQ==, - } - peerDependencies: - lexical: 0.13.1 - dependencies: - '@lexical/list': 0.13.1(lexical@0.13.1) - '@lexical/selection': 0.13.1(lexical@0.13.1) - '@lexical/table': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - dev: false - - /@lexical/yjs@0.13.1(lexical@0.13.1)(yjs@13.6.15): - resolution: - { - integrity: sha512-4GbqQM+PwNTV59AZoNrfTe/0rLjs+cX6Y6yAdZSRPBwr5L3JzYeU1TTcFCVQTtsE7KF8ddVP8sD7w9pi8rOWLA==, - } - peerDependencies: - lexical: 0.13.1 - yjs: '>=13.5.22' + '@lexical/text@0.20.0': dependencies: - '@lexical/offset': 0.13.1(lexical@0.13.1) - lexical: 0.13.1 - yjs: 13.6.15 - dev: false + lexical: 0.20.0 - /@monaco-editor/loader@1.4.0(monaco-editor@0.48.0): - resolution: - { - integrity: sha512-00ioBig0x642hytVspPl7DbQyaSWRaolYie/UFNjoTdvoKPzo6xrXLhTk9ixgIKcLH5b5vDOjVNiGyY+uDCUlg==, - } - peerDependencies: - monaco-editor: '>= 0.21.0 < 1' + '@lexical/utils@0.20.0': + dependencies: + '@lexical/list': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/table': 0.20.0 + lexical: 0.20.0 + + '@lexical/yjs@0.20.0(yjs@13.6.27)': + dependencies: + '@lexical/offset': 0.20.0 + '@lexical/selection': 0.20.0 + lexical: 0.20.0 + yjs: 13.6.27 + + '@monaco-editor/loader@1.7.0': dependencies: - monaco-editor: 0.48.0 state-local: 1.0.7 - dev: false - /@monaco-editor/react@4.5.1(monaco-editor@0.48.0)(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-NNDFdP+2HojtNhCkRfE6/D6ro6pBNihaOzMbGK84lNWzRu+CfBjwzGt4jmnqimLuqp5yE5viHS2vi+QOAnD5FQ==, - } - peerDependencies: - monaco-editor: '>= 0.25.0 < 1' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@monaco-editor/react@4.6.0(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@monaco-editor/loader': 1.4.0(monaco-editor@0.48.0) - monaco-editor: 0.48.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false + '@monaco-editor/loader': 1.7.0 + monaco-editor: 0.55.1 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - /@mongodb-js/saslprep@1.1.5: - resolution: - { - integrity: sha512-XLNOMH66KhJzUJNwT/qlMnS4WsNDWD5ASdyaSH3EtK+F4r/CFGa3jT4GNi4mfOitGvWXtdLgQJkQjxSVrio+jA==, - } - requiresBuild: true + '@mongodb-js/saslprep@1.4.0': dependencies: sparse-bitfield: 3.0.3 - dev: false - optional: true - /@next/env@14.3.0-canary.7: - resolution: - { - integrity: sha512-FXmIhrOXLCAC3CFfsphwr9B4sd42TdJWJ95UgvXJErnS2XgT0iv0BtMULybWOBzpJVWQavYzl+CkFDQC2EFJiw==, - } - dev: false - - /@next/swc-darwin-arm64@14.3.0-canary.7: - resolution: - { - integrity: sha512-AwYIdp0HHJQFI+LDAzTp7gj4suyl9KZgWFvHd79DljG4DLJMVEDb669AXpwV1m9WgVzWgnUsTJgF/XHDhaIRfg==, - } - engines: { node: '>= 10' } - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: false - optional: true + '@next/env@15.5.8': {} - /@next/swc-darwin-x64@14.3.0-canary.7: - resolution: - { - integrity: sha512-NeXcmZdRycTNG3aMROgaTVuW3espy8CX9dVC7KQT9/YnRPItNhP/maU7kgIA5C43bgjCgwg1f9ABNB2NX99eWw==, - } - engines: { node: '>= 10' } - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: false + '@next/swc-darwin-arm64@15.5.7': optional: true - /@next/swc-linux-arm64-gnu@14.3.0-canary.7: - resolution: - { - integrity: sha512-Qct3FFELGR8Vl97GBHuend1X94ykEzF7Cvyi8TX1I1uCZZHhRzHzJMo7TjrI+YNbJF804sc/+VsNxVxR197/Nw==, - } - engines: { node: '>= 10' } - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false + '@next/swc-darwin-x64@15.5.7': optional: true - /@next/swc-linux-arm64-musl@14.3.0-canary.7: - resolution: - { - integrity: sha512-sxLnN5QKp8JwEuABmArZ6uV8wjO9ozt7qbne/Y1zhKIyYl+WSgoPxznJz98bEGjd7o7sntSm1djYwZd+Ra1v1w==, - } - engines: { node: '>= 10' } - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false + '@next/swc-linux-arm64-gnu@15.5.7': optional: true - /@next/swc-linux-x64-gnu@14.3.0-canary.7: - resolution: - { - integrity: sha512-s3i4CFmsk7QcSDyScrMOQQ9EZPNRzkw2pUXI/SweKQC0qLXQ6agthCH0Ks69b/niMxzG+P4pen50qm1svsBHog==, - } - engines: { node: '>= 10' } - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false + '@next/swc-linux-arm64-musl@15.5.7': optional: true - /@next/swc-linux-x64-musl@14.3.0-canary.7: - resolution: - { - integrity: sha512-I3Js4g8ylkFGUb8ICI4ya1j89D/jw/SnItrGce03UWQhOdczlWixSFabE2RqSYtVM+cOWVLJ8SSmeoi98YQPNg==, - } - engines: { node: '>= 10' } - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false + '@next/swc-linux-x64-gnu@15.5.7': optional: true - /@next/swc-win32-arm64-msvc@14.3.0-canary.7: - resolution: - { - integrity: sha512-H8iTu2VPOmm2QXhWRkItS3Vfieh52pdg6IGBnm4xp+RJ6UVBEluTT2VDYB7vqjPnbof/dq6woflZkq2/KujSrQ==, - } - engines: { node: '>= 10' } - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: false + '@next/swc-linux-x64-musl@15.5.7': optional: true - /@next/swc-win32-ia32-msvc@14.3.0-canary.7: - resolution: - { - integrity: sha512-OwdUlF/N+nJRXqFdwdRtSuilFlBDctIJSV30TdNNTdnTCCYtI9cyrJ+8Sx3EVhQQVTxySPUgmhJitgmgyDMmkQ==, - } - engines: { node: '>= 10' } - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: false + '@next/swc-win32-arm64-msvc@15.5.7': optional: true - /@next/swc-win32-x64-msvc@14.3.0-canary.7: - resolution: - { - integrity: sha512-pirSoMkVeWG7VuBEw6kISWUT1AaMeRj6TtcDuj7lJUoD2AQUO17yxRXMDLJ7Kf1ymOAxOEUf+Toys9V8NpSjKA==, - } - engines: { node: '>= 10' } - cpu: [x64] - os: [win32] - requiresBuild: true - dev: false + '@next/swc-win32-x64-msvc@15.5.7': optional: true - /@nodelib/fs.scandir@2.1.5: - resolution: - { - integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, - } - engines: { node: '>= 8' } + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - /@nodelib/fs.stat@2.0.5: - resolution: - { - integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, - } - engines: { node: '>= 8' } + '@nodelib/fs.stat@2.0.5': {} - /@nodelib/fs.walk@1.2.8: - resolution: - { - integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, - } - engines: { node: '>= 8' } + '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 + fastq: 1.19.1 - /@payloadcms/db-mongodb@3.0.0-beta.19(payload@3.0.0-beta.19): - resolution: - { - integrity: sha512-kT0dro1yipzi7cdJUN9fHJjq+F3mw9mchqgOoWSgYs0cQKaEzrgI6GmS7/7wOtZdVH4XaJtPYYEKfxy+nCk5Xw==, - } - peerDependencies: - payload: 3.0.0-beta.19 + '@payloadcms/db-mongodb@3.0.0-beta.135(payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))': dependencies: - bson-objectid: 2.0.4 - deepmerge: 4.3.1 - get-port: 5.1.1 http-status: 1.6.2 - mongoose: 6.12.3 - mongoose-paginate-v2: 1.7.22 - payload: 3.0.0-beta.19(@swc/core@1.4.17)(@swc/types@0.1.6)(graphql@16.8.1) + mongoose: 8.8.1 + mongoose-aggregate-paginate-v2: 1.1.2 + mongoose-paginate-v2: 1.8.5 + payload: 3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) prompts: 2.4.2 - uuid: 9.0.0 + uuid: 10.0.0 transitivePeerDependencies: - - aws-crt + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks - supports-color - dev: false - /@payloadcms/graphql@3.0.0-beta.19(graphql@16.8.1)(payload@3.0.0-beta.19): - resolution: - { - integrity: sha512-gjE2CootXE++II3Dyw1PSHNSKoz/jQxPP9PqpdV1KPFzvMEXx+gjtcl2qS5golTDirnbMeO3857VU0Qsu/qM4A==, - } - peerDependencies: - graphql: ^16.8.1 - payload: 3.0.0-beta.19 + '@payloadcms/graphql@3.0.0-beta.135(graphql@16.12.0)(payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(typescript@5.9.3)': dependencies: - graphql: 16.8.1 - graphql-scalars: 1.22.2(graphql@16.8.1) - payload: 3.0.0-beta.19(@swc/core@1.4.17)(@swc/types@0.1.6)(graphql@16.8.1) + graphql: 16.12.0 + graphql-scalars: 1.22.2(graphql@16.12.0) + payload: 3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) pluralize: 8.0.0 - dev: false - - /@payloadcms/next@3.0.0-beta.19(@types/react@18.3.1)(file-type@16.5.4)(graphql@16.8.1)(http-status@1.6.2)(monaco-editor@0.48.0)(next@14.3.0-canary.7)(payload@3.0.0-beta.19)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.2): - resolution: - { - integrity: sha512-P31yvkhDhamca+ISNgOVVU2hwvnumkkUInMnGdmw2St88ltfcMyglR8BCXyyLtCxOvz/gra45lszc9Gu17bq+w==, - } - engines: { node: '>=18.20.2' } - peerDependencies: - file-type: 16.5.4 - graphql: ^16.8.1 - http-status: 1.6.2 - next: ^14.3.0-canary.7 - payload: 3.0.0-beta.19 - dependencies: - '@dnd-kit/core': 6.0.8(react-dom@18.3.1)(react@18.3.1) - '@payloadcms/graphql': 3.0.0-beta.19(graphql@16.8.1)(payload@3.0.0-beta.19) - '@payloadcms/translations': 3.0.0-beta.19 - '@payloadcms/ui': 3.0.0-beta.19(@types/react@18.3.1)(monaco-editor@0.48.0)(next@14.3.0-canary.7)(payload@3.0.0-beta.19)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.2) - '@types/busboy': 1.5.3 + ts-essentials: 10.0.3(typescript@5.9.3) + tsx: 4.19.2 + transitivePeerDependencies: + - typescript + + '@payloadcms/next@3.0.0-beta.135(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@payloadcms/graphql': 3.0.0-beta.135(graphql@16.12.0)(payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(typescript@5.9.3) + '@payloadcms/translations': 3.0.0-beta.135 + '@payloadcms/ui': 3.0.0-beta.135(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) busboy: 1.6.0 - deep-equal: 2.2.2 - file-type: 16.5.4 - graphql: 16.8.1 - graphql-http: 1.22.1(graphql@16.8.1) + file-type: 19.3.0 + graphql: 16.12.0 + graphql-http: 1.22.4(graphql@16.12.0) graphql-playground-html: 1.6.30 http-status: 1.6.2 - next: 14.3.0-canary.7(react-dom@18.3.1)(react@18.3.1) - path-to-regexp: 6.2.2 - payload: 3.0.0-beta.19(@swc/core@1.4.17)(@swc/types@0.1.6)(graphql@16.8.1) - qs: 6.11.2 - react-diff-viewer-continued: 3.2.6(react-dom@18.3.1)(react@18.3.1) - react-toastify: 8.2.0(react-dom@18.3.1)(react@18.3.1) - sass: 1.75.0 - ws: 8.17.0 + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + path-to-regexp: 6.3.0 + payload: 3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + qs-esm: 7.0.2 + react-diff-viewer-continued: 3.2.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + sass: 1.77.4 + sonner: 1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + uuid: 10.0.0 transitivePeerDependencies: - '@types/react' - - bufferutil - monaco-editor - react - react-dom - - react-native - - scheduler - - utf-8-validate - dev: false - - /@payloadcms/richtext-lexical@3.0.0-beta.19(@lexical/clipboard@0.13.1)(@payloadcms/next@3.0.0-beta.19)(@payloadcms/translations@3.0.0-beta.19)(@payloadcms/ui@3.0.0-beta.19)(payload@3.0.0-beta.19)(react-dom@18.3.1)(react@18.3.1)(typescript@5.4.5)(yjs@13.6.15): - resolution: - { - integrity: sha512-IdiIQx3LP6ym+wzADk62fqTZtRlNdJuQFAD3WWWSgknGU8ktJ957VKSNT+ng2dA65MQMMhct81kXTAFRcaHrsA==, - } - engines: { node: '>=18.20.2' } - peerDependencies: - '@payloadcms/next': 3.0.0-beta.19 - '@payloadcms/translations': 3.0.0-beta.19 - '@payloadcms/ui': 3.0.0-beta.19 - payload: 3.0.0-beta.19 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@faceless-ui/modal': 2.0.2(react-dom@18.3.1)(react@18.3.1) - '@lexical/headless': 0.13.1(lexical@0.13.1) - '@lexical/link': 0.13.1(lexical@0.13.1) - '@lexical/list': 0.13.1(lexical@0.13.1) - '@lexical/mark': 0.13.1(lexical@0.13.1) - '@lexical/markdown': 0.13.1(@lexical/clipboard@0.13.1)(@lexical/selection@0.13.1)(lexical@0.13.1) - '@lexical/react': 0.13.1(lexical@0.13.1)(react-dom@18.3.1)(react@18.3.1)(yjs@13.6.15) - '@lexical/rich-text': 0.13.1(@lexical/clipboard@0.13.1)(@lexical/selection@0.13.1)(@lexical/utils@0.13.1)(lexical@0.13.1) - '@lexical/selection': 0.13.1(lexical@0.13.1) - '@lexical/utils': 0.13.1(lexical@0.13.1) - '@payloadcms/next': 3.0.0-beta.19(@types/react@18.3.1)(file-type@16.5.4)(graphql@16.8.1)(http-status@1.6.2)(monaco-editor@0.48.0)(next@14.3.0-canary.7)(payload@3.0.0-beta.19)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.2) - '@payloadcms/translations': 3.0.0-beta.19 - '@payloadcms/ui': 3.0.0-beta.19(@types/react@18.3.1)(monaco-editor@0.48.0)(next@14.3.0-canary.7)(payload@3.0.0-beta.19)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.2) + - supports-color + - typescript + + '@payloadcms/richtext-lexical@3.0.0-beta.135(9b4a47f79fb2e59c857749218ee42c77)': + dependencies: + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@lexical/headless': 0.20.0 + '@lexical/link': 0.20.0 + '@lexical/list': 0.20.0 + '@lexical/mark': 0.20.0 + '@lexical/markdown': 0.20.0 + '@lexical/react': 0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.27) + '@lexical/rich-text': 0.20.0 + '@lexical/selection': 0.20.0 + '@lexical/table': 0.20.0 + '@lexical/utils': 0.20.0 + '@payloadcms/next': 3.0.0-beta.135(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + '@payloadcms/translations': 3.0.0-beta.135 + '@payloadcms/ui': 3.0.0-beta.135(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + '@types/uuid': 10.0.0 + acorn: 8.12.1 bson-objectid: 2.0.4 - classnames: 2.5.1 - deep-equal: 2.2.3 - json-schema: 0.4.0 - lexical: 0.13.1 - lodash: 4.17.21 - payload: 3.0.0-beta.19(@swc/core@1.4.17)(@swc/types@0.1.6)(graphql@16.8.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-error-boundary: 4.0.12(react@18.3.1) - ts-essentials: 7.0.3(typescript@5.4.5) + dequal: 2.0.3 + escape-html: 1.0.3 + lexical: 0.20.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-mdx-jsx: 3.1.3 + micromark-extension-mdx-jsx: 3.0.1 + payload: 3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 4.0.13(react@19.2.2) + ts-essentials: 10.0.3(typescript@5.9.3) + uuid: 10.0.0 transitivePeerDependencies: - - '@lexical/clipboard' + - '@types/react' + - monaco-editor + - next + - supports-color - typescript - - yjs - dev: false - - /@payloadcms/translations@3.0.0-beta.19: - resolution: - { - integrity: sha512-io9LDjOHd8cMzdv63V3kQkyERJZJSG0edlYbVgRBJKzKkNOwJhNcw32duWZenyyHJmvqEuHHaTuri/S6d7ABpQ==, - } - dev: false - - /@payloadcms/ui@3.0.0-beta.19(@types/react@18.3.1)(monaco-editor@0.48.0)(next@14.3.0-canary.7)(payload@3.0.0-beta.19)(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.2): - resolution: - { - integrity: sha512-CF9tdez++XVLrB35yOCLifgkXoNMuV+cEVH59d3SCm4dhepwahXPbyTxh99lLiF+zHHSEmgR4aMa0rtCXYDwbw==, - } - engines: { node: '>=18.20.2' } - peerDependencies: - next: ^14.3.0-canary.7 - payload: 3.0.0-beta.19 - react: ^18.0.0 - react-dom: ^18.0.0 - dependencies: - '@dnd-kit/core': 6.0.8(react-dom@18.3.1)(react@18.3.1) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8)(react@18.3.1) - '@faceless-ui/modal': 2.0.2(react-dom@18.3.1)(react@18.3.1) - '@faceless-ui/scroll-info': 1.3.0(react-dom@18.3.1)(react@18.3.1) - '@faceless-ui/window-info': 2.1.2(react-dom@18.3.1)(react@18.3.1) - '@monaco-editor/react': 4.5.1(monaco-editor@0.48.0)(react-dom@18.3.1)(react@18.3.1) - '@payloadcms/translations': 3.0.0-beta.19 + + '@payloadcms/translations@3.0.0-beta.135': + dependencies: + date-fns: 4.1.0 + + '@payloadcms/ui@3.0.0-beta.135(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@monaco-editor/react': 4.6.0(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@payloadcms/translations': 3.0.0-beta.135 body-scroll-lock: 4.0.0-beta.0 bson-objectid: 2.0.4 - date-fns: 3.3.1 - deep-equal: 2.2.2 - flatley: 5.2.0 + date-fns: 4.1.0 + dequal: 2.0.3 md5: 2.3.0 - next: 14.3.0-canary.7(react-dom@18.3.1)(react@18.3.1) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) object-to-formdata: 4.5.1 - payload: 3.0.0-beta.19(@swc/core@1.4.17)(@swc/types@0.1.6)(graphql@16.8.1) - qs: 6.11.2 - react: 18.3.1 - react-animate-height: 2.1.2(react-dom@18.3.1)(react@18.3.1) - react-datepicker: 6.2.0(react-dom@18.3.1)(react@18.3.1) - react-dom: 18.3.1(react@18.3.1) - react-image-crop: 10.1.8(react@18.3.1) - react-select: 5.7.4(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) - react-toastify: 10.0.4(react-dom@18.3.1)(react@18.3.1) - use-context-selector: 1.4.1(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.2) - uuid: 9.0.1 + payload: 3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + qs-esm: 7.0.2 + react: 19.2.2 + react-animate-height: 2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-datepicker: 6.9.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-dom: 19.2.2(react@19.2.2) + react-image-crop: 10.1.8(react@19.2.2) + react-select: 5.8.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + scheduler: 0.0.0-experimental-3edc000d-20240926 + sonner: 1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + ts-essentials: 10.0.3(typescript@5.9.3) + use-context-selector: 2.0.0(react@19.2.2)(scheduler@0.0.0-experimental-3edc000d-20240926) + uuid: 10.0.0 transitivePeerDependencies: - '@types/react' - monaco-editor - - react-native - - scheduler - dev: false - - /@pkgjs/parseargs@0.11.0: - resolution: - { - integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, - } - engines: { node: '>=14' } - requiresBuild: true - optional: true - - /@sideway/address@4.1.5: - resolution: - { - integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==, - } - dependencies: - '@hapi/hoek': 9.3.0 - dev: false - - /@sideway/formula@3.0.1: - resolution: - { - integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==, - } - dev: false - - /@sideway/pinpoint@2.0.0: - resolution: - { - integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==, - } - dev: false - - /@smithy/abort-controller@2.2.0: - resolution: - { - integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/config-resolver@2.2.0: - resolution: - { - integrity: sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-config-provider': 2.3.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/core@1.4.2: - resolution: - { - integrity: sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/credential-provider-imds@2.3.0: - resolution: - { - integrity: sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/fetch-http-handler@2.5.0: - resolution: - { - integrity: sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==, - } - requiresBuild: true - dependencies: - '@smithy/protocol-http': 3.3.0 - '@smithy/querystring-builder': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/util-base64': 2.3.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/hash-node@2.2.0: - resolution: - { - integrity: sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/invalid-dependency@2.2.0: - resolution: - { - integrity: sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==, - } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true + - supports-color + - typescript - /@smithy/is-array-buffer@2.2.0: - resolution: - { - integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true + '@swc/helpers@0.5.15': dependencies: - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/middleware-content-length@2.2.0: - resolution: - { - integrity: sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/middleware-endpoint@2.5.1: - resolution: - { - integrity: sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/middleware-serde': 2.3.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/middleware-retry@2.3.1: - resolution: - { - integrity: sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/service-error-classification': 2.1.5 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - tslib: 2.6.2 - uuid: 9.0.1 - dev: false - optional: true - - /@smithy/middleware-serde@2.3.0: - resolution: - { - integrity: sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/middleware-stack@2.2.0: - resolution: - { - integrity: sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/node-config-provider@2.3.0: - resolution: - { - integrity: sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/node-http-handler@2.5.0: - resolution: - { - integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/abort-controller': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/querystring-builder': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/property-provider@2.2.0: - resolution: - { - integrity: sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/protocol-http@3.3.0: - resolution: - { - integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/querystring-builder@2.2.0: - resolution: - { - integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - '@smithy/util-uri-escape': 2.2.0 - tslib: 2.6.2 - dev: false - optional: true + tslib: 2.8.1 - /@smithy/querystring-parser@2.2.0: - resolution: - { - integrity: sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true + '@tokenizer/token@0.3.0': {} - /@smithy/service-error-classification@2.1.5: - resolution: - { - integrity: sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true + '@types/acorn@4.0.6': dependencies: - '@smithy/types': 2.12.0 - dev: false - optional: true - - /@smithy/shared-ini-file-loader@2.4.0: - resolution: - { - integrity: sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/signature-v4@2.3.0: - resolution: - { - integrity: sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/is-array-buffer': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/util-hex-encoding': 2.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-uri-escape': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/smithy-client@2.5.1: - resolution: - { - integrity: sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-stack': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 - dev: false - optional: true + '@types/estree': 1.0.8 - /@smithy/types@2.12.0: - resolution: - { - integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true + '@types/busboy@1.5.4': dependencies: - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/url-parser@2.2.0: - resolution: - { - integrity: sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==, - } - requiresBuild: true - dependencies: - '@smithy/querystring-parser': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true + '@types/node': 20.19.26 - /@smithy/util-base64@2.3.0: - resolution: - { - integrity: sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/util-body-length-browser@2.2.0: - resolution: - { - integrity: sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==, - } - requiresBuild: true + '@types/debug@4.1.12': dependencies: - tslib: 2.6.2 - dev: false - optional: true + '@types/ms': 2.1.0 - /@smithy/util-body-length-node@2.3.0: - resolution: - { - integrity: sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true + '@types/estree-jsx@1.0.5': dependencies: - tslib: 2.6.2 - dev: false - optional: true + '@types/estree': 1.0.8 - /@smithy/util-buffer-from@2.2.0: - resolution: - { - integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/is-array-buffer': 2.2.0 - tslib: 2.6.2 - dev: false - optional: true + '@types/estree@1.0.8': {} - /@smithy/util-config-provider@2.3.0: - resolution: - { - integrity: sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true + '@types/hast@3.0.4': dependencies: - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/util-defaults-mode-browser@2.2.1: - resolution: - { - integrity: sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==, - } - engines: { node: '>= 10.0.0' } - requiresBuild: true - dependencies: - '@smithy/property-provider': 2.2.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - bowser: 2.11.0 - tslib: 2.6.2 - dev: false - optional: true + '@types/unist': 3.0.3 - /@smithy/util-defaults-mode-node@2.3.1: - resolution: - { - integrity: sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==, - } - engines: { node: '>= 10.0.0' } - requiresBuild: true - dependencies: - '@smithy/config-resolver': 2.2.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true + '@types/json-schema@7.0.15': {} - /@smithy/util-endpoints@1.2.0: - resolution: - { - integrity: sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==, - } - engines: { node: '>= 14.0.0' } - requiresBuild: true - dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true + '@types/lodash@4.17.21': {} - /@smithy/util-hex-encoding@2.2.0: - resolution: - { - integrity: sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true + '@types/mdast@4.0.4': dependencies: - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/util-middleware@2.2.0: - resolution: - { - integrity: sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/util-retry@2.2.0: - resolution: - { - integrity: sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==, - } - engines: { node: '>= 14.0.0' } - requiresBuild: true - dependencies: - '@smithy/service-error-classification': 2.1.5 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: false - optional: true + '@types/unist': 3.0.3 - /@smithy/util-stream@2.2.0: - resolution: - { - integrity: sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/types': 2.12.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-hex-encoding': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - dev: false - optional: true + '@types/ms@2.1.0': {} - /@smithy/util-uri-escape@2.2.0: - resolution: - { - integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true + '@types/node@20.19.26': dependencies: - tslib: 2.6.2 - dev: false - optional: true - - /@smithy/util-utf8@2.3.0: - resolution: - { - integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==, - } - engines: { node: '>=14.0.0' } - requiresBuild: true - dependencies: - '@smithy/util-buffer-from': 2.2.0 - tslib: 2.6.2 - dev: false - optional: true - - /@swc-node/core@1.13.0(@swc/core@1.4.17)(@swc/types@0.1.6): - resolution: - { - integrity: sha512-lFPD4nmy4ifAOVMChFjwlpXN5KQXvegqeyuzz1KQz42q1lf+cL3Qux1/GteGuZjh8HC+Rj1RdNrHpE/MCfJSTw==, - } - engines: { node: '>= 10' } - peerDependencies: - '@swc/core': '>= 1.3' - '@swc/types': '>= 0.1' - dependencies: - '@swc/core': 1.4.17 - '@swc/types': 0.1.6 - dev: false - - /@swc-node/sourcemap-support@0.5.0: - resolution: - { - integrity: sha512-fbhjL5G0YvFoWwNhWleuBUfotiX+USiA9oJqu9STFw+Hb0Cgnddn+HVS/K5fI45mn92e8V+cHD2jgFjk4w2T9Q==, - } - dependencies: - source-map-support: 0.5.21 - tslib: 2.6.2 - dev: false - - /@swc/core-darwin-arm64@1.4.17: - resolution: - { - integrity: sha512-HVl+W4LezoqHBAYg2JCqR+s9ife9yPfgWSj37iIawLWzOmuuJ7jVdIB7Ee2B75bEisSEKyxRlTl6Y1Oq3owBgw==, - } - engines: { node: '>=10' } - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: false - optional: true + undici-types: 6.21.0 - /@swc/core-darwin-x64@1.4.17: - resolution: - { - integrity: sha512-WYRO9Fdzq4S/he8zjW5I95G1zcvyd9yyD3Tgi4/ic84P5XDlSMpBDpBLbr/dCPjmSg7aUXxNQqKqGkl6dQxYlA==, - } - engines: { node: '>=10' } - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: false - optional: true + '@types/parse-json@4.0.2': {} - /@swc/core-linux-arm-gnueabihf@1.4.17: - resolution: - { - integrity: sha512-cgbvpWOvtMH0XFjvwppUCR+Y+nf6QPaGu6AQ5hqCP+5Lv2zO5PG0RfasC4zBIjF53xgwEaaWmGP5/361P30X8Q==, - } - engines: { node: '>=10' } - cpu: [arm] - os: [linux] - requiresBuild: true - dev: false - optional: true + '@types/react-dom@19.2.1(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 - /@swc/core-linux-arm64-gnu@1.4.17: - resolution: - { - integrity: sha512-l7zHgaIY24cF9dyQ/FOWbmZDsEj2a9gRFbmgx2u19e3FzOPuOnaopFj0fRYXXKCmtdx+anD750iBIYnTR+pq/Q==, - } - engines: { node: '>=10' } - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false - optional: true + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 - /@swc/core-linux-arm64-musl@1.4.17: - resolution: - { - integrity: sha512-qhH4gr9gAlVk8MBtzXbzTP3BJyqbAfUOATGkyUtohh85fPXQYuzVlbExix3FZXTwFHNidGHY8C+ocscI7uDaYw==, - } - engines: { node: '>=10' } - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false - optional: true + '@types/react@19.2.1': + dependencies: + csstype: 3.2.3 - /@swc/core-linux-x64-gnu@1.4.17: - resolution: - { - integrity: sha512-vRDFATL1oN5oZMImkwbgSHEkp8xG1ofEASBypze01W1Tqto8t+yo6gsp69wzCZBlxldsvPpvFZW55Jq0Rn+UnA==, - } - engines: { node: '>=10' } - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false + '@types/trusted-types@2.0.7': optional: true - /@swc/core-linux-x64-musl@1.4.17: - resolution: - { - integrity: sha512-zQNPXAXn3nmPqv54JVEN8k2JMEcMTQ6veVuU0p5O+A7KscJq+AGle/7ZQXzpXSfUCXlLMX4wvd+rwfGhh3J4cw==, - } - engines: { node: '>=10' } - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false - optional: true + '@types/unist@2.0.11': {} - /@swc/core-win32-arm64-msvc@1.4.17: - resolution: - { - integrity: sha512-z86n7EhOwyzxwm+DLE5NoLkxCTme2lq7QZlDjbQyfCxOt6isWz8rkW5QowTX8w9Rdmk34ncrjSLvnHOeLY17+w==, - } - engines: { node: '>=10' } - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: false - optional: true + '@types/unist@3.0.3': {} - /@swc/core-win32-ia32-msvc@1.4.17: - resolution: - { - integrity: sha512-JBwuSTJIgiJJX6wtr4wmXbfvOswHFj223AumUrK544QV69k60FJ9q2adPW9Csk+a8wm1hLxq4HKa2K334UHJ/g==, - } - engines: { node: '>=10' } - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: false - optional: true + '@types/uuid@10.0.0': {} - /@swc/core-win32-x64-msvc@1.4.17: - resolution: - { - integrity: sha512-jFkOnGQamtVDBm3MF5Kq1lgW8vx4Rm1UvJWRUfg+0gx7Uc3Jp3QMFeMNw/rDNQYRDYPG3yunCC+2463ycd5+dg==, - } - engines: { node: '>=10' } - cpu: [x64] - os: [win32] - requiresBuild: true - dev: false - optional: true + '@types/webidl-conversions@7.0.3': {} - /@swc/core@1.4.17: - resolution: - { - integrity: sha512-tq+mdWvodMBNBBZbwFIMTVGYHe9N7zvEaycVVjfvAx20k1XozHbHhRv+9pEVFJjwRxLdXmtvFZd3QZHRAOpoNQ==, - } - engines: { node: '>=10' } - requiresBuild: true - peerDependencies: - '@swc/helpers': ^0.5.0 - peerDependenciesMeta: - '@swc/helpers': - optional: true + '@types/whatwg-url@11.0.5': dependencies: - '@swc/counter': 0.1.3 - '@swc/types': 0.1.6 - optionalDependencies: - '@swc/core-darwin-arm64': 1.4.17 - '@swc/core-darwin-x64': 1.4.17 - '@swc/core-linux-arm-gnueabihf': 1.4.17 - '@swc/core-linux-arm64-gnu': 1.4.17 - '@swc/core-linux-arm64-musl': 1.4.17 - '@swc/core-linux-x64-gnu': 1.4.17 - '@swc/core-linux-x64-musl': 1.4.17 - '@swc/core-win32-arm64-msvc': 1.4.17 - '@swc/core-win32-ia32-msvc': 1.4.17 - '@swc/core-win32-x64-msvc': 1.4.17 - dev: false - - /@swc/counter@0.1.3: - resolution: - { - integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==, - } - dev: false - - /@swc/helpers@0.5.5: - resolution: - { - integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==, - } - dependencies: - '@swc/counter': 0.1.3 - tslib: 2.6.2 - dev: false - - /@swc/types@0.1.6: - resolution: - { - integrity: sha512-/JLo/l2JsT/LRd80C3HfbmVpxOAJ11FO2RCEslFrgzLltoP9j8XIbsyDcfCt2WWyX+CM96rBoNM+IToAkFOugg==, - } - dependencies: - '@swc/counter': 0.1.3 - dev: false - - /@tokenizer/token@0.3.0: - resolution: - { - integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==, - } - dev: false - - /@types/busboy@1.5.3: - resolution: - { - integrity: sha512-YMBLFN/xBD8bnqywIlGyYqsNFXu6bsiY7h3Ae0kO17qEuTjsqeyYMRPSUDacIKIquws2Y6KjmxAyNx8xB3xQbw==, - } - dependencies: - '@types/node': 20.12.7 - dev: false - - /@types/glob@7.2.0: - resolution: - { - integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==, - } - dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 20.12.7 - dev: false - - /@types/json-schema@7.0.15: - resolution: - { - integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, - } - dev: false - - /@types/lodash@4.17.0: - resolution: - { - integrity: sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==, - } - dev: false - - /@types/minimatch@5.1.2: - resolution: - { - integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==, - } - dev: false - - /@types/needle@3.3.0: - resolution: - { - integrity: sha512-UFIuc1gdyzAqeVUYpSL+cliw2MmU/ZUhVZKE7Zo4wPbgc8hbljeKSnn6ls6iG8r5jpegPXLUIhJ+Wb2kLVs8cg==, - } - dependencies: - '@types/node': 20.12.7 - dev: false - - /@types/node@20.12.7: - resolution: - { - integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==, - } - dependencies: - undici-types: 5.26.5 - - /@types/parse-json@4.0.2: - resolution: - { - integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==, - } - dev: false - - /@types/prettier@2.7.3: - resolution: - { - integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==, - } - dev: false - - /@types/probe-image-size@7.2.4: - resolution: - { - integrity: sha512-HVqYj3L+D+S/6qpQRv5qMxrD/5pglzZuhP7ZIqgVSZ+Ck4z1TCFkNIRG8WesFueQTqWFTSgkkAl6f8lwxFPQSw==, - } - dependencies: - '@types/needle': 3.3.0 - '@types/node': 20.12.7 - dev: false - - /@types/prop-types@15.7.12: - resolution: - { - integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==, - } - - /@types/react-dom@18.3.0: - resolution: - { - integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==, - } - dependencies: - '@types/react': 18.3.1 - dev: true - - /@types/react-transition-group@4.4.10: - resolution: - { - integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==, - } - dependencies: - '@types/react': 18.3.1 - dev: false - - /@types/react@18.3.1: - resolution: - { - integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==, - } - dependencies: - '@types/prop-types': 15.7.12 - csstype: 3.1.3 - - /@types/webidl-conversions@7.0.3: - resolution: - { - integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==, - } - dev: false - - /@types/whatwg-url@8.2.2: - resolution: - { - integrity: sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==, - } - dependencies: - '@types/node': 20.12.7 '@types/webidl-conversions': 7.0.3 - dev: false - - /abort-controller@3.0.0: - resolution: - { - integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==, - } - engines: { node: '>=6.5' } - dependencies: - event-target-shim: 5.0.1 - dev: false - - /ajv-formats@2.1.1(ajv@8.12.0): - resolution: - { - integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==, - } - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - dependencies: - ajv: 8.12.0 - dev: false - /ajv@8.12.0: - resolution: - { - integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==, - } + acorn@8.12.1: {} + + ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: false - - /ansi-regex@5.0.1: - resolution: - { - integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, - } - engines: { node: '>=8' } - - /ansi-regex@6.0.1: - resolution: - { - integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==, - } - engines: { node: '>=12' } - - /ansi-styles@3.2.1: - resolution: - { - integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, - } - engines: { node: '>=4' } - dependencies: - color-convert: 1.9.3 - dev: false - - /ansi-styles@4.3.0: - resolution: - { - integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, - } - engines: { node: '>=8' } - dependencies: - color-convert: 2.0.1 - /ansi-styles@6.2.1: - resolution: - { - integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==, - } - engines: { node: '>=12' } - - /any-promise@1.3.0: - resolution: - { - integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, - } - - /anymatch@3.1.3: - resolution: - { - integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, - } - engines: { node: '>= 8' } + any-promise@1.3.0: {} + + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - /arg@5.0.2: - resolution: - { - integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==, - } - - /argparse@2.0.1: - resolution: - { - integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, - } - dev: false - - /array-buffer-byte-length@1.0.1: - resolution: - { - integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - is-array-buffer: 3.0.4 - dev: false - - /atomic-sleep@1.0.0: - resolution: - { - integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==, - } - engines: { node: '>=8.0.0' } - dev: false - - /atomically@1.7.0: - resolution: - { - integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==, - } - engines: { node: '>=10.12.0' } - dev: false - - /autoprefixer@10.4.19(postcss@8.4.38): - resolution: - { - integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==, - } - engines: { node: ^10 || ^12 || >=14 } - hasBin: true - peerDependencies: - postcss: ^8.1.0 + arg@5.0.2: {} + + argparse@2.0.1: {} + + atomic-sleep@1.0.0: {} + + autoprefixer@10.4.22(postcss@8.5.6): dependencies: - browserslist: 4.23.0 - caniuse-lite: 1.0.30001613 - fraction.js: 4.3.7 + browserslist: 4.28.1 + caniuse-lite: 1.0.30001760 + fraction.js: 5.3.4 normalize-range: 0.1.2 - picocolors: 1.0.0 - postcss: 8.4.38 + picocolors: 1.1.1 + postcss: 8.5.6 postcss-value-parser: 4.2.0 - dev: true - - /available-typed-arrays@1.0.7: - resolution: - { - integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==, - } - engines: { node: '>= 0.4' } - dependencies: - possible-typed-array-names: 1.0.0 - dev: false - - /b4a@1.6.6: - resolution: - { - integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==, - } - dev: false - - /babel-plugin-macros@3.1.0: - resolution: - { - integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==, - } - engines: { node: '>=10', npm: '>=6' } - dependencies: - '@babel/runtime': 7.24.4 + + b4a@1.7.3: {} + + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.28.4 cosmiconfig: 7.1.0 - resolve: 1.22.8 - dev: false - - /balanced-match@1.0.2: - resolution: - { - integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, - } - - /bare-events@2.2.2: - resolution: - { - integrity: sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==, - } - requiresBuild: true - dev: false + resolve: 1.22.11 + + bare-events@2.8.2: {} + + bare-fs@4.5.2: + dependencies: + bare-events: 2.8.2 + bare-path: 3.0.0 + bare-stream: 2.7.0(bare-events@2.8.2) + bare-url: 2.3.2 + fast-fifo: 1.3.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a optional: true - /bare-fs@2.3.0: - resolution: - { - integrity: sha512-TNFqa1B4N99pds2a5NYHR15o0ZpdNKbAeKTE/+G6ED/UeOavv8RY3dr/Fu99HW3zU3pXpo2kDNO8Sjsm2esfOw==, - } - requiresBuild: true - dependencies: - bare-events: 2.2.2 - bare-path: 2.1.2 - bare-stream: 1.0.0 - dev: false + bare-os@3.6.2: optional: true - /bare-os@2.3.0: - resolution: - { - integrity: sha512-oPb8oMM1xZbhRQBngTgpcQ5gXw6kjOaRsSWsIeNyRxGed2w/ARyP7ScBYpWR1qfX2E5rS3gBw6OWcSQo+s+kUg==, - } - requiresBuild: true - dev: false + bare-path@3.0.0: + dependencies: + bare-os: 3.6.2 optional: true - /bare-path@2.1.2: - resolution: - { - integrity: sha512-o7KSt4prEphWUHa3QUwCxUI00R86VdjiuxmJK0iNVDHYPGo+HsDaVCnqCmPbf/MiW1ok8F4p3m8RTHlWk8K2ig==, - } - requiresBuild: true + bare-stream@2.7.0(bare-events@2.8.2): dependencies: - bare-os: 2.3.0 - dev: false + streamx: 2.23.0 + optionalDependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a optional: true - /bare-stream@1.0.0: - resolution: - { - integrity: sha512-KhNUoDL40iP4gFaLSsoGE479t0jHijfYdIcxRn/XtezA2BaUD0NRf/JGRpsMq6dMNM+SrCrB0YSSo/5wBY4rOQ==, - } - requiresBuild: true + bare-url@2.3.2: dependencies: - streamx: 2.16.1 - dev: false + bare-path: 3.0.0 optional: true - /base64-js@1.5.1: - resolution: - { - integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==, - } - dev: false - - /binary-extensions@2.3.0: - resolution: - { - integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==, - } - engines: { node: '>=8' } - - /bl@4.1.0: - resolution: - { - integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==, - } + base64-js@1.5.1: {} + + baseline-browser-mapping@2.9.6: {} + + binary-extensions@2.3.0: {} + + bl@4.1.0: dependencies: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 - dev: false - - /body-scroll-lock@3.1.5: - resolution: - { - integrity: sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg==, - } - dev: false - - /body-scroll-lock@4.0.0-beta.0: - resolution: - { - integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==, - } - dev: false - - /bowser@2.11.0: - resolution: - { - integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==, - } - requiresBuild: true - dev: false - optional: true - /brace-expansion@1.1.11: - resolution: - { - integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, - } - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: false - - /brace-expansion@2.0.1: - resolution: - { - integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==, - } - dependencies: - balanced-match: 1.0.2 - - /braces@3.0.2: - resolution: - { - integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==, - } - engines: { node: '>=8' } - dependencies: - fill-range: 7.0.1 - - /browserslist@4.23.0: - resolution: - { - integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==, - } - engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } - hasBin: true - dependencies: - caniuse-lite: 1.0.30001613 - electron-to-chromium: 1.4.750 - node-releases: 2.0.14 - update-browserslist-db: 1.0.13(browserslist@4.23.0) - dev: true - - /bson-objectid@2.0.4: - resolution: - { - integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==, - } - dev: false - - /bson@4.7.2: - resolution: - { - integrity: sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==, - } - engines: { node: '>=6.9.0' } + body-scroll-lock@4.0.0-beta.0: {} + + braces@3.0.3: dependencies: - buffer: 5.7.1 - dev: false - - /buffer-equal-constant-time@1.0.1: - resolution: - { - integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==, - } - dev: false - - /buffer-from@1.1.2: - resolution: - { - integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, - } - dev: false - - /buffer@5.7.1: - resolution: - { - integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==, - } + fill-range: 7.1.1 + + browserslist@4.28.1: dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: false + baseline-browser-mapping: 2.9.6 + caniuse-lite: 1.0.30001760 + electron-to-chromium: 1.5.267 + node-releases: 2.0.27 + update-browserslist-db: 1.2.2(browserslist@4.28.1) + + bson-objectid@2.0.4: {} - /buffer@6.0.3: - resolution: - { - integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==, - } + bson@6.10.4: {} + + buffer@5.7.1: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: false - /busboy@1.6.0: - resolution: - { - integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==, - } - engines: { node: '>=10.16.0' } + busboy@1.6.0: dependencies: streamsearch: 1.1.0 - dev: false - /call-bind@1.0.7: - resolution: - { - integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==, - } - engines: { node: '>= 0.4' } - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - set-function-length: 1.2.2 - dev: false - - /call-me-maybe@1.0.2: - resolution: - { - integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==, - } - dev: false - - /callsites@3.1.0: - resolution: - { - integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, - } - engines: { node: '>=6' } - dev: false - - /camelcase-css@2.0.1: - resolution: - { - integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==, - } - engines: { node: '>= 6' } - - /caniuse-lite@1.0.30001613: - resolution: - { - integrity: sha512-BNjJULJfOONQERivfxte7alLfeLW4QnwHvNW4wEcLEbXfV6VSCYvr+REbf2Sojv8tC1THpjPXBxWgDbq4NtLWg==, - } - - /chalk@2.4.2: - resolution: - { - integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, - } - engines: { node: '>=4' } - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - dev: false - - /charenc@0.0.2: - resolution: - { - integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==, - } - dev: false - - /chokidar@3.6.0: - resolution: - { - integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==, - } - engines: { node: '>= 8.10.0' } + callsites@3.1.0: {} + + camelcase-css@2.0.1: {} + + caniuse-lite@1.0.30001760: {} + + ccount@2.0.1: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + charenc@0.0.2: {} + + chokidar@3.6.0: dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -3523,4146 +3464,1494 @@ packages: optionalDependencies: fsevents: 2.3.3 - /chownr@1.1.4: - resolution: - { - integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==, - } - dev: false - - /ci-info@4.0.0: - resolution: - { - integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==, - } - engines: { node: '>=8' } - dev: false - - /class-variance-authority@0.7.0: - resolution: - { - integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==, - } - dependencies: - clsx: 2.0.0 - dev: false - - /classnames@2.5.1: - resolution: - { - integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==, - } - dev: false - - /cli-color@2.0.4: - resolution: - { - integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==, - } - engines: { node: '>=0.10' } - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - memoizee: 0.4.15 - timers-ext: 0.1.7 - dev: false - - /client-only@0.0.1: - resolution: - { - integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==, - } - dev: false - - /clsx@1.2.1: - resolution: - { - integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==, - } - engines: { node: '>=6' } - dev: false - - /clsx@2.0.0: - resolution: - { - integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==, - } - engines: { node: '>=6' } - dev: false - - /clsx@2.1.1: - resolution: - { - integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==, - } - engines: { node: '>=6' } - dev: false - - /color-convert@1.9.3: - resolution: - { - integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, - } - dependencies: - color-name: 1.1.3 - dev: false - - /color-convert@2.0.1: - resolution: - { - integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, - } - engines: { node: '>=7.0.0' } + chownr@1.1.4: {} + + ci-info@4.3.1: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + classnames@2.5.1: {} + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + color-convert@2.0.1: dependencies: color-name: 1.1.4 - /color-name@1.1.3: - resolution: - { - integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, - } - dev: false - - /color-name@1.1.4: - resolution: - { - integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, - } - - /color-string@1.9.1: - resolution: - { - integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==, - } + color-name@1.1.4: {} + + color-string@1.9.1: dependencies: color-name: 1.1.4 - simple-swizzle: 0.2.2 - dev: false + simple-swizzle: 0.2.4 - /color@4.2.3: - resolution: - { - integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==, - } - engines: { node: '>=12.5.0' } + color@4.2.3: dependencies: color-convert: 2.0.1 color-string: 1.9.1 - dev: false - - /colorette@2.0.20: - resolution: - { - integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==, - } - dev: false - - /commander@2.20.3: - resolution: - { - integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, - } - dev: false - - /commander@4.1.1: - resolution: - { - integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==, - } - engines: { node: '>= 6' } - - /concat-map@0.0.1: - resolution: - { - integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, - } - dev: false - - /conf@10.2.0: - resolution: - { - integrity: sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==, - } - engines: { node: '>=12' } - dependencies: - ajv: 8.12.0 - ajv-formats: 2.1.1(ajv@8.12.0) - atomically: 1.7.0 - debounce-fn: 4.0.0 - dot-prop: 6.0.1 - env-paths: 2.2.1 - json-schema-typed: 7.0.3 - onetime: 5.1.2 - pkg-up: 3.1.0 - semver: 7.6.0 - dev: false - - /console-table-printer@2.11.2: - resolution: - { - integrity: sha512-uuUHie0sfPP542TKGzPFal0W1wo1beuKAqIZdaavcONx8OoqdnJRKjkinbRTOta4FaCa1RcIL+7mMJWX3pQGVg==, - } - dependencies: - simple-wcswidth: 1.0.1 - dev: false - - /convert-source-map@1.9.0: - resolution: - { - integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==, - } - dev: false - - /cosmiconfig@7.1.0: - resolution: - { - integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==, - } - engines: { node: '>=10' } + + colorette@2.0.20: {} + + commander@2.20.3: {} + + commander@4.1.1: {} + + console-table-printer@2.12.1: + dependencies: + simple-wcswidth: 1.1.2 + + convert-source-map@1.9.0: {} + + cosmiconfig@7.1.0: dependencies: '@types/parse-json': 4.0.2 - import-fresh: 3.3.0 + import-fresh: 3.3.1 parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.2 - dev: false - - /cross-env@7.0.3: - resolution: - { - integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==, - } - engines: { node: '>=10.14', npm: '>=6', yarn: '>=1' } - hasBin: true + + croner@9.0.0: {} + + cross-env@7.0.3: dependencies: - cross-spawn: 7.0.3 - dev: false + cross-spawn: 7.0.6 - /cross-spawn@7.0.3: - resolution: - { - integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==, - } - engines: { node: '>= 8' } + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - /crypt@0.0.2: - resolution: - { - integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==, - } - dev: false - - /cssesc@3.0.0: - resolution: - { - integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==, - } - engines: { node: '>=4' } - hasBin: true + crypt@0.0.2: {} - /cssfilter@0.0.10: - resolution: - { - integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==, - } - dev: false - - /csstype@3.1.3: - resolution: - { - integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==, - } - - /d@1.0.2: - resolution: - { - integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==, - } - engines: { node: '>=0.12' } - dependencies: - es5-ext: 0.10.64 - type: 2.7.2 - dev: false - - /dataloader@2.2.2: - resolution: - { - integrity: sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==, - } - dev: false - - /date-fns@3.3.1: - resolution: - { - integrity: sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==, - } - dev: false - - /dateformat@4.6.3: - resolution: - { - integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==, - } - dev: false - - /debounce-fn@4.0.0: - resolution: - { - integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==, - } - engines: { node: '>=10' } - dependencies: - mimic-fn: 3.1.0 - dev: false - - /debug@4.3.4: - resolution: - { - integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==, - } - engines: { node: '>=6.0' } - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + cssesc@3.0.0: {} + + cssfilter@0.0.10: {} + + csstype@3.2.3: {} + + dataloader@2.2.2: {} + + date-fns@3.6.0: {} + + date-fns@4.1.0: {} + + dateformat@4.6.3: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.2.0: dependencies: - ms: 2.1.2 - dev: false + character-entities: 2.0.2 - /decompress-response@6.0.0: - resolution: - { - integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==, - } - engines: { node: '>=10' } + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 - dev: false - - /deep-equal@2.2.2: - resolution: - { - integrity: sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==, - } - dependencies: - array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 - es-get-iterator: 1.1.3 - get-intrinsic: 1.2.4 - is-arguments: 1.1.1 - is-array-buffer: 3.0.4 - is-date-object: 1.0.5 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.3 - isarray: 2.0.5 - object-is: 1.1.6 - object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 - side-channel: 1.0.6 - which-boxed-primitive: 1.0.2 - which-collection: 1.0.2 - which-typed-array: 1.1.15 - dev: false - - /deep-equal@2.2.3: - resolution: - { - integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==, - } - engines: { node: '>= 0.4' } - dependencies: - array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 - es-get-iterator: 1.1.3 - get-intrinsic: 1.2.4 - is-arguments: 1.1.1 - is-array-buffer: 3.0.4 - is-date-object: 1.0.5 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.3 - isarray: 2.0.5 - object-is: 1.1.6 - object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 - side-channel: 1.0.6 - which-boxed-primitive: 1.0.2 - which-collection: 1.0.2 - which-typed-array: 1.1.15 - dev: false - - /deep-extend@0.6.0: - resolution: - { - integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==, - } - engines: { node: '>=4.0.0' } - dev: false - - /deepmerge@4.3.1: - resolution: - { - integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==, - } - engines: { node: '>=0.10.0' } - dev: false - - /define-data-property@1.1.4: - resolution: - { - integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, - } - engines: { node: '>= 0.4' } - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - gopd: 1.0.1 - dev: false - - /define-properties@1.2.1: - resolution: - { - integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==, - } - engines: { node: '>= 0.4' } - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - dev: false - - /detect-libc@2.0.3: - resolution: - { - integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==, - } - engines: { node: '>=8' } - dev: false - - /didyoumean@1.2.2: - resolution: - { - integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==, - } - - /diff@5.2.0: - resolution: - { - integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==, - } - engines: { node: '>=0.3.1' } - dev: false - - /dlv@1.1.3: - resolution: - { - integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==, - } - - /dom-helpers@5.2.1: - resolution: - { - integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==, - } - dependencies: - '@babel/runtime': 7.24.4 - csstype: 3.1.3 - dev: false - - /dot-prop@6.0.1: - resolution: - { - integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==, - } - engines: { node: '>=10' } - dependencies: - is-obj: 2.0.0 - dev: false - - /dotenv@16.4.5: - resolution: - { - integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==, - } - engines: { node: '>=12' } - dev: true - - /dotenv@8.6.0: - resolution: - { - integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==, - } - engines: { node: '>=10' } - dev: false - - /eastasianwidth@0.2.0: - resolution: - { - integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, - } - - /ecdsa-sig-formatter@1.0.11: - resolution: - { - integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==, - } + + deep-extend@0.6.0: {} + + deepmerge@4.3.1: {} + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + devlop@1.1.0: dependencies: - safe-buffer: 5.2.1 - dev: false - - /electron-to-chromium@1.4.750: - resolution: - { - integrity: sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==, - } - dev: true - - /emoji-regex@8.0.0: - resolution: - { - integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, - } - - /emoji-regex@9.2.2: - resolution: - { - integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, - } - - /end-of-stream@1.4.4: - resolution: - { - integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==, - } + dequal: 2.0.3 + + didyoumean@1.2.2: {} + + diff@5.2.0: {} + + dlv@1.1.3: {} + + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.28.4 + csstype: 3.2.3 + + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + dotenv@16.6.1: {} + + electron-to-chromium@1.5.267: {} + + end-of-stream@1.4.5: dependencies: once: 1.4.0 - dev: false - - /env-paths@2.2.1: - resolution: - { - integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==, - } - engines: { node: '>=6' } - dev: false - - /error-ex@1.3.2: - resolution: - { - integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==, - } + + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 - dev: false - - /es-define-property@1.0.0: - resolution: - { - integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==, - } - engines: { node: '>= 0.4' } - dependencies: - get-intrinsic: 1.2.4 - dev: false - - /es-errors@1.3.0: - resolution: - { - integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, - } - engines: { node: '>= 0.4' } - dev: false - - /es-get-iterator@1.1.3: - resolution: - { - integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==, - } - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - is-arguments: 1.1.1 - is-map: 2.0.3 - is-set: 2.0.3 - is-string: 1.0.7 - isarray: 2.0.5 - stop-iteration-iterator: 1.0.0 - dev: false - - /es5-ext@0.10.64: - resolution: - { - integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==, - } - engines: { node: '>=0.10' } - requiresBuild: true - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 - next-tick: 1.1.0 - dev: false - - /es6-iterator@2.0.3: - resolution: - { - integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==, - } - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 - dev: false - - /es6-symbol@3.1.4: - resolution: - { - integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==, - } - engines: { node: '>=0.12' } - dependencies: - d: 1.0.2 - ext: 1.7.0 - dev: false - - /es6-weak-map@2.0.3: - resolution: - { - integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==, - } - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - dev: false - - /esbuild@0.19.12: - resolution: - { - integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==, - } - engines: { node: '>=12' } - hasBin: true - requiresBuild: true + + esbuild@0.23.1: optionalDependencies: - '@esbuild/aix-ppc64': 0.19.12 - '@esbuild/android-arm': 0.19.12 - '@esbuild/android-arm64': 0.19.12 - '@esbuild/android-x64': 0.19.12 - '@esbuild/darwin-arm64': 0.19.12 - '@esbuild/darwin-x64': 0.19.12 - '@esbuild/freebsd-arm64': 0.19.12 - '@esbuild/freebsd-x64': 0.19.12 - '@esbuild/linux-arm': 0.19.12 - '@esbuild/linux-arm64': 0.19.12 - '@esbuild/linux-ia32': 0.19.12 - '@esbuild/linux-loong64': 0.19.12 - '@esbuild/linux-mips64el': 0.19.12 - '@esbuild/linux-ppc64': 0.19.12 - '@esbuild/linux-riscv64': 0.19.12 - '@esbuild/linux-s390x': 0.19.12 - '@esbuild/linux-x64': 0.19.12 - '@esbuild/netbsd-x64': 0.19.12 - '@esbuild/openbsd-x64': 0.19.12 - '@esbuild/sunos-x64': 0.19.12 - '@esbuild/win32-arm64': 0.19.12 - '@esbuild/win32-ia32': 0.19.12 - '@esbuild/win32-x64': 0.19.12 - dev: true - - /escalade@3.1.2: - resolution: - { - integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==, - } - engines: { node: '>=6' } - dev: true - - /escape-string-regexp@1.0.5: - resolution: - { - integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, - } - engines: { node: '>=0.8.0' } - dev: false - - /escape-string-regexp@4.0.0: - resolution: - { - integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, - } - engines: { node: '>=10' } - dev: false - - /esniff@2.0.1: - resolution: - { - integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==, - } - engines: { node: '>=0.10' } - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.2 - dev: false - - /event-emitter@0.3.5: - resolution: - { - integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==, - } - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - dev: false - - /event-target-shim@5.0.1: - resolution: - { - integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==, - } - engines: { node: '>=6' } - dev: false - - /events@3.3.0: - resolution: - { - integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==, - } - engines: { node: '>=0.8.x' } - dev: false - - /expand-template@2.0.3: - resolution: - { - integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==, - } - engines: { node: '>=6' } - dev: false - - /ext@1.7.0: - resolution: - { - integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==, - } - dependencies: - type: 2.7.2 - dev: false - - /fast-copy@3.0.2: - resolution: - { - integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==, - } - dev: false - - /fast-deep-equal@3.1.3: - resolution: - { - integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, - } - dev: false - - /fast-fifo@1.3.2: - resolution: - { - integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==, - } - dev: false - - /fast-glob@3.3.2: - resolution: - { - integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==, - } - engines: { node: '>=8.6.0' } + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + + esbuild@0.27.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.1 + '@esbuild/android-arm': 0.27.1 + '@esbuild/android-arm64': 0.27.1 + '@esbuild/android-x64': 0.27.1 + '@esbuild/darwin-arm64': 0.27.1 + '@esbuild/darwin-x64': 0.27.1 + '@esbuild/freebsd-arm64': 0.27.1 + '@esbuild/freebsd-x64': 0.27.1 + '@esbuild/linux-arm': 0.27.1 + '@esbuild/linux-arm64': 0.27.1 + '@esbuild/linux-ia32': 0.27.1 + '@esbuild/linux-loong64': 0.27.1 + '@esbuild/linux-mips64el': 0.27.1 + '@esbuild/linux-ppc64': 0.27.1 + '@esbuild/linux-riscv64': 0.27.1 + '@esbuild/linux-s390x': 0.27.1 + '@esbuild/linux-x64': 0.27.1 + '@esbuild/netbsd-arm64': 0.27.1 + '@esbuild/netbsd-x64': 0.27.1 + '@esbuild/openbsd-arm64': 0.27.1 + '@esbuild/openbsd-x64': 0.27.1 + '@esbuild/openharmony-arm64': 0.27.1 + '@esbuild/sunos-x64': 0.27.1 + '@esbuild/win32-arm64': 0.27.1 + '@esbuild/win32-ia32': 0.27.1 + '@esbuild/win32-x64': 0.27.1 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@4.0.0: {} + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + events-universal@1.0.1: + dependencies: + bare-events: 2.8.2 + transitivePeerDependencies: + - bare-abort-controller + + expand-template@2.0.3: {} + + fast-copy@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-fifo@1.3.2: {} + + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 - - /fast-redact@3.5.0: - resolution: - { - integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==, - } - engines: { node: '>=6' } - dev: false - - /fast-safe-stringify@2.1.1: - resolution: - { - integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==, - } - dev: false - - /fast-xml-parser@4.2.5: - resolution: - { - integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==, - } - hasBin: true - requiresBuild: true + micromatch: 4.0.8 + + fast-redact@3.5.0: {} + + fast-safe-stringify@2.1.1: {} + + fast-uri@3.1.0: {} + + fastq@1.19.1: dependencies: - strnum: 1.0.5 - dev: false - optional: true + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-type@19.3.0: + dependencies: + strtok3: 8.1.0 + token-types: 6.1.1 + uint8array-extras: 1.5.0 - /fastq@1.17.1: - resolution: - { - integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==, - } - dependencies: - reusify: 1.0.4 - - /file-type@16.5.4: - resolution: - { - integrity: sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==, - } - engines: { node: '>=10' } - dependencies: - readable-web-to-node-stream: 3.0.2 - strtok3: 6.3.0 - token-types: 4.2.1 - dev: false - - /fill-range@7.0.1: - resolution: - { - integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==, - } - engines: { node: '>=8' } + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - /find-root@1.1.0: - resolution: - { - integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==, - } - dev: false - - /find-up@3.0.0: - resolution: - { - integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==, - } - engines: { node: '>=6' } - dependencies: - locate-path: 3.0.0 - dev: false - - /find-up@4.1.0: - resolution: - { - integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==, - } - engines: { node: '>=8' } - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - dev: false - - /flatley@5.2.0: - resolution: - { - integrity: sha512-vsb0/03uIHu7/3jRqABweblFUJMLokz1uMrcgFlvx6OAr6V3FiSic2iXeiJCj+cciTiQeumSDsIFAAnN1yvu4w==, - } + find-root@1.1.0: {} + + focus-trap@7.5.4: dependencies: - is-buffer: 1.1.6 - dev: false - - /focus-trap@6.9.4: - resolution: - { - integrity: sha512-v2NTsZe2FF59Y+sDykKY+XjqZ0cPfhq/hikWVL88BqLivnNiEffAsac6rP6H45ff9wG9LL5ToiDqrLEP9GX9mw==, - } - dependencies: - tabbable: 5.3.3 - dev: false - - /for-each@0.3.3: - resolution: - { - integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==, - } - dependencies: - is-callable: 1.2.7 - dev: false - - /foreground-child@3.1.1: - resolution: - { - integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==, - } - engines: { node: '>=14' } - dependencies: - cross-spawn: 7.0.3 - signal-exit: 4.1.0 - - /fraction.js@4.3.7: - resolution: - { - integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==, - } - dev: true - - /fs-constants@1.0.0: - resolution: - { - integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==, - } - dev: false - - /fs.realpath@1.0.0: - resolution: - { - integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==, - } - dev: false - - /fsevents@2.3.3: - resolution: - { - integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, - } - engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } - os: [darwin] - requiresBuild: true + tabbable: 6.3.0 + + fraction.js@5.3.4: {} + + fs-constants@1.0.0: {} + + fsevents@2.3.3: optional: true - /function-bind@1.1.2: - resolution: - { - integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, - } - - /functions-have-names@1.2.3: - resolution: - { - integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==, - } - dev: false - - /get-intrinsic@1.2.4: - resolution: - { - integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==, - } - engines: { node: '>= 0.4' } - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - hasown: 2.0.2 - dev: false - - /get-port@5.1.1: - resolution: - { - integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==, - } - engines: { node: '>=8' } - dev: false - - /get-stdin@8.0.0: - resolution: - { - integrity: sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==, - } - engines: { node: '>=10' } - dev: false - - /get-tsconfig@4.7.3: - resolution: - { - integrity: sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==, - } + function-bind@1.1.2: {} + + get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 - /github-from-package@0.0.0: - resolution: - { - integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==, - } - dev: false - - /glob-parent@5.1.2: - resolution: - { - integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, - } - engines: { node: '>= 6' } + get-tsconfig@4.8.1: dependencies: - is-glob: 4.0.3 + resolve-pkg-maps: 1.0.0 + + github-from-package@0.0.0: {} - /glob-parent@6.0.2: - resolution: - { - integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, - } - engines: { node: '>=10.13.0' } + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - /glob-promise@4.2.2(glob@7.2.3): - resolution: - { - integrity: sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==, - } - engines: { node: '>=12' } - peerDependencies: - glob: ^7.1.6 - dependencies: - '@types/glob': 7.2.0 - glob: 7.2.3 - dev: false - - /glob@10.3.12: - resolution: - { - integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==, - } - engines: { node: '>=16 || 14 >=14.17' } - hasBin: true + glob-parent@6.0.2: dependencies: - foreground-child: 3.1.1 - jackspeak: 2.3.6 - minimatch: 9.0.4 - minipass: 7.0.4 - path-scurry: 1.10.2 + is-glob: 4.0.3 - /glob@7.2.3: - resolution: - { - integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==, - } - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: false - - /glob@8.1.0: - resolution: - { - integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==, - } - engines: { node: '>=12' } - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - dev: false - - /gopd@1.0.1: - resolution: - { - integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==, - } - dependencies: - get-intrinsic: 1.2.4 - dev: false - - /graceful-fs@4.2.11: - resolution: - { - integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, - } - dev: false - - /graphql-http@1.22.1(graphql@16.8.1): - resolution: - { - integrity: sha512-4Jor+LRbA7SfSaw7dfDUs2UBzvWg3cKrykfHRgKsOIvQaLuf+QOcG2t3Mx5N9GzSNJcuqMqJWz0ta5+BryEmXg==, - } - engines: { node: '>=12' } - peerDependencies: - graphql: '>=0.11 <=16' + graphql-http@1.22.4(graphql@16.12.0): dependencies: - graphql: 16.8.1 - dev: false + graphql: 16.12.0 - /graphql-playground-html@1.6.30: - resolution: - { - integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==, - } + graphql-playground-html@1.6.30: dependencies: xss: 1.0.15 - dev: false - - /graphql-scalars@1.22.2(graphql@16.8.1): - resolution: - { - integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==, - } - engines: { node: '>=10' } - peerDependencies: - graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + + graphql-scalars@1.22.2(graphql@16.12.0): dependencies: - graphql: 16.8.1 - tslib: 2.6.2 - dev: false - - /graphql@16.8.1: - resolution: - { - integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==, - } - engines: { node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0 } - dev: false - - /has-bigints@1.0.2: - resolution: - { - integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==, - } - dev: false - - /has-flag@3.0.0: - resolution: - { - integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, - } - engines: { node: '>=4' } - dev: false - - /has-property-descriptors@1.0.2: - resolution: - { - integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==, - } - dependencies: - es-define-property: 1.0.0 - dev: false - - /has-proto@1.0.3: - resolution: - { - integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==, - } - engines: { node: '>= 0.4' } - dev: false - - /has-symbols@1.0.3: - resolution: - { - integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==, - } - engines: { node: '>= 0.4' } - dev: false - - /has-tostringtag@1.0.2: - resolution: - { - integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, - } - engines: { node: '>= 0.4' } - dependencies: - has-symbols: 1.0.3 - dev: false - - /hasown@2.0.2: - resolution: - { - integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, - } - engines: { node: '>= 0.4' } + graphql: 16.12.0 + tslib: 2.8.1 + + graphql@16.12.0: {} + + hasown@2.0.2: dependencies: function-bind: 1.1.2 - /help-me@4.2.0: - resolution: - { - integrity: sha512-TAOnTB8Tz5Dw8penUuzHVrKNKlCIbwwbHnXraNJxPwf8LRtE2HlM84RYuezMFcwOJmoYOCWVDyJ8TQGxn9PgxA==, - } - dependencies: - glob: 8.1.0 - readable-stream: 3.6.2 - dev: false + help-me@5.0.0: {} - /hoist-non-react-statics@3.3.2: - resolution: - { - integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==, - } + hoist-non-react-statics@3.3.2: dependencies: react-is: 16.13.1 - dev: false - - /http-status@1.6.2: - resolution: - { - integrity: sha512-oUExvfNckrpTpDazph7kNG8sQi5au3BeTo0idaZFXEhTaJKu7GNJCLHI0rYY2wljm548MSTM+Ljj/c6anqu2zQ==, - } - engines: { node: '>= 0.4.0' } - dev: false - - /ieee754@1.2.1: - resolution: - { - integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==, - } - dev: false - - /image-size@1.1.1: - resolution: - { - integrity: sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==, - } - engines: { node: '>=16.x' } - hasBin: true + + http-status@1.6.2: {} + + ieee754@1.2.1: {} + + image-size@1.2.1: dependencies: queue: 6.0.2 - dev: false - - /immutable@4.3.5: - resolution: - { - integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==, - } - dev: false - - /import-fresh@3.3.0: - resolution: - { - integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==, - } - engines: { node: '>=6' } + + immutable@4.3.7: {} + + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: false - /inflight@1.0.6: - resolution: - { - integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==, - } + inherits@2.0.4: {} + + ini@1.3.8: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: false - - /inherits@2.0.4: - resolution: - { - integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==, - } - dev: false - - /ini@1.3.8: - resolution: - { - integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==, - } - dev: false - - /internal-slot@1.0.7: - resolution: - { - integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==, - } - engines: { node: '>= 0.4' } - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.0.6 - dev: false - - /ip-address@9.0.5: - resolution: - { - integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==, - } - engines: { node: '>= 12' } - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 - dev: false - - /is-arguments@1.1.1: - resolution: - { - integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - dev: false - - /is-array-buffer@3.0.4: - resolution: - { - integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - dev: false - - /is-arrayish@0.2.1: - resolution: - { - integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, - } - dev: false - - /is-arrayish@0.3.2: - resolution: - { - integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==, - } - dev: false - - /is-bigint@1.0.4: - resolution: - { - integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==, - } - dependencies: - has-bigints: 1.0.2 - dev: false - - /is-binary-path@2.1.0: - resolution: - { - integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, - } - engines: { node: '>=8' } + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-arrayish@0.2.1: {} + + is-arrayish@0.3.4: {} + + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 - /is-boolean-object@1.1.2: - resolution: - { - integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - dev: false - - /is-buffer@1.1.6: - resolution: - { - integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==, - } - dev: false - - /is-callable@1.2.7: - resolution: - { - integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==, - } - engines: { node: '>= 0.4' } - dev: false - - /is-core-module@2.13.1: - resolution: - { - integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==, - } + is-buffer@1.1.6: {} + + is-core-module@2.16.1: dependencies: hasown: 2.0.2 - /is-date-object@1.0.5: - resolution: - { - integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==, - } - engines: { node: '>= 0.4' } - dependencies: - has-tostringtag: 1.0.2 - dev: false - - /is-extglob@2.1.1: - resolution: - { - integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, - } - engines: { node: '>=0.10.0' } - - /is-fullwidth-code-point@3.0.0: - resolution: - { - integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, - } - engines: { node: '>=8' } - - /is-glob@4.0.3: - resolution: - { - integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, - } - engines: { node: '>=0.10.0' } + is-decimal@2.0.1: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - /is-map@2.0.3: - resolution: - { - integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==, - } - engines: { node: '>= 0.4' } - dev: false - - /is-number-object@1.0.7: - resolution: - { - integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==, - } - engines: { node: '>= 0.4' } - dependencies: - has-tostringtag: 1.0.2 - dev: false - - /is-number@7.0.0: - resolution: - { - integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, - } - engines: { node: '>=0.12.0' } - - /is-obj@2.0.0: - resolution: - { - integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==, - } - engines: { node: '>=8' } - dev: false - - /is-promise@2.2.2: - resolution: - { - integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==, - } - dev: false - - /is-regex@1.1.4: - resolution: - { - integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - dev: false - - /is-set@2.0.3: - resolution: - { - integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==, - } - engines: { node: '>= 0.4' } - dev: false - - /is-shared-array-buffer@1.0.3: - resolution: - { - integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - dev: false - - /is-string@1.0.7: - resolution: - { - integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==, - } - engines: { node: '>= 0.4' } - dependencies: - has-tostringtag: 1.0.2 - dev: false - - /is-symbol@1.0.4: - resolution: - { - integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==, - } - engines: { node: '>= 0.4' } - dependencies: - has-symbols: 1.0.3 - dev: false - - /is-weakmap@2.0.2: - resolution: - { - integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==, - } - engines: { node: '>= 0.4' } - dev: false - - /is-weakset@2.0.3: - resolution: - { - integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - dev: false - - /isarray@2.0.5: - resolution: - { - integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, - } - dev: false - - /isexe@2.0.0: - resolution: - { - integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, - } - - /isomorphic.js@0.2.5: - resolution: - { - integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==, - } - dev: false - - /jackspeak@2.3.6: - resolution: - { - integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==, - } - engines: { node: '>=14' } - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 + is-hexadecimal@2.0.1: {} - /jiti@1.21.0: - resolution: - { - integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==, - } - hasBin: true + is-number@7.0.0: {} - /joi@17.13.0: - resolution: - { - integrity: sha512-9qcrTyoBmFZRNHeVP4edKqIUEgFzq7MHvTNSDuHSqkpOPtiBkgNgcmTSqmiw1kw9tdKaiddvIDv/eCJDxmqWCA==, - } - dependencies: - '@hapi/hoek': 9.3.0 - '@hapi/topo': 5.1.0 - '@sideway/address': 4.1.5 - '@sideway/formula': 3.0.1 - '@sideway/pinpoint': 2.0.0 - dev: false - - /joycon@3.1.1: - resolution: - { - integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==, - } - engines: { node: '>=10' } - dev: false - - /js-tokens@4.0.0: - resolution: - { - integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, - } - dev: false - - /js-yaml@4.1.0: - resolution: - { - integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, - } - hasBin: true + isexe@2.0.0: {} + + isomorphic.js@0.2.5: {} + + jiti@1.21.7: {} + + jose@5.9.6: {} + + joycon@3.1.1: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: dependencies: argparse: 2.0.1 - dev: false - - /jsbn@1.1.0: - resolution: - { - integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==, - } - dev: false - - /json-parse-even-better-errors@2.3.1: - resolution: - { - integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==, - } - dev: false - - /json-schema-to-typescript@11.0.3: - resolution: - { - integrity: sha512-EaEE9Y4VZ8b9jW5zce5a9L3+p4C9AqgIRHbNVDJahfMnoKzcd4sDb98BLxLdQhJEuRAXyKLg4H66NKm80W8ilg==, - } - engines: { node: '>=12.0.0' } - hasBin: true + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-to-typescript@15.0.3: dependencies: - '@bcherny/json-schema-ref-parser': 9.0.9 + '@apidevtools/json-schema-ref-parser': 11.9.3 '@types/json-schema': 7.0.15 - '@types/lodash': 4.17.0 - '@types/prettier': 2.7.3 - cli-color: 2.0.4 - get-stdin: 8.0.0 - glob: 7.2.3 - glob-promise: 4.2.2(glob@7.2.3) + '@types/lodash': 4.17.21 is-glob: 4.0.3 + js-yaml: 4.1.1 lodash: 4.17.21 minimist: 1.2.8 - mkdirp: 1.0.4 - mz: 2.7.0 - prettier: 2.8.8 - dev: false - - /json-schema-traverse@1.0.0: - resolution: - { - integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==, - } - dev: false - - /json-schema-typed@7.0.3: - resolution: - { - integrity: sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==, - } - dev: false - - /json-schema@0.4.0: - resolution: - { - integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==, - } - dev: false - - /jsonwebtoken@9.0.1: - resolution: - { - integrity: sha512-K8wx7eJ5TPvEjuiVSkv167EVboBDv9PZdDoF7BgeQnBLVvZWW9clr2PsQHVJDTKaEIH5JBIwHujGcHp7GgI2eg==, - } - engines: { node: '>=12', npm: '>=6' } - dependencies: - jws: 3.2.2 - lodash: 4.17.21 - ms: 2.1.3 - semver: 7.6.0 - dev: false + prettier: 3.7.4 + tinyglobby: 0.2.15 - /jwa@1.4.1: - resolution: - { - integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==, - } - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - dev: false + json-schema-traverse@1.0.0: {} - /jws@3.2.2: - resolution: - { - integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==, - } - dependencies: - jwa: 1.4.1 - safe-buffer: 5.2.1 - dev: false - - /kareem@2.5.1: - resolution: - { - integrity: sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==, - } - engines: { node: '>=12.0.0' } - dev: false - - /kleur@3.0.3: - resolution: - { - integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==, - } - engines: { node: '>=6' } - dev: false - - /lexical@0.13.1: - resolution: - { - integrity: sha512-jaqRYzVEfBKbX4FwYpd/g+MyOjRaraAel0iQsTrwvx3hyN0bswUZuzb6H6nGlFSjcdrc77wKpyKwoWj4aUd+Bw==, - } - dev: false - - /lib0@0.2.93: - resolution: - { - integrity: sha512-M5IKsiFJYulS+8Eal8f+zAqf5ckm1vffW0fFDxfgxJ+uiVopvDdd3PxJmz0GsVi3YNO7QCFSq0nAsiDmNhLj9Q==, - } - engines: { node: '>=16' } - hasBin: true + kareem@2.6.3: {} + + kleur@3.0.3: {} + + lexical@0.20.0: {} + + lib0@0.2.114: dependencies: isomorphic.js: 0.2.5 - dev: false - - /lilconfig@2.1.0: - resolution: - { - integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==, - } - engines: { node: '>=10' } - - /lilconfig@3.1.1: - resolution: - { - integrity: sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==, - } - engines: { node: '>=14' } - - /lines-and-columns@1.2.4: - resolution: - { - integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, - } - - /locate-path@3.0.0: - resolution: - { - integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==, - } - engines: { node: '>=6' } - dependencies: - p-locate: 3.0.0 - path-exists: 3.0.0 - dev: false - - /locate-path@5.0.0: - resolution: - { - integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==, - } - engines: { node: '>=8' } - dependencies: - p-locate: 4.1.0 - dev: false - - /lodash@4.17.21: - resolution: - { - integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==, - } - dev: false - - /loose-envify@1.4.0: - resolution: - { - integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, - } - hasBin: true + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + lodash@4.17.21: {} + + longest-streak@3.1.0: {} + + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 - dev: false - - /lru-cache@10.2.1: - resolution: - { - integrity: sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==, - } - engines: { node: 14 || >=16.14 } - - /lru-cache@6.0.0: - resolution: - { - integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==, - } - engines: { node: '>=10' } - dependencies: - yallist: 4.0.0 - dev: false - - /lru-queue@0.1.0: - resolution: - { - integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==, - } - dependencies: - es5-ext: 0.10.64 - dev: false - - /lucide-react@0.376.0(react@18.3.1): - resolution: - { - integrity: sha512-g91IX3ERD6yUR1TL2dsL4BkcGygpZz/EsqjAeL/kcRQV0EApIOr/9eBfKhYOVyQIcGGuotFGjF3xKLHMEz+b7g==, - } - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 + + lucide-react@0.376.0(react@19.2.2): dependencies: - react: 18.3.1 - dev: false + react: 19.2.2 - /md5@2.3.0: - resolution: - { - integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==, - } + marked@14.0.0: {} + + md5@2.3.0: dependencies: charenc: 0.0.2 crypt: 0.0.2 is-buffer: 1.1.6 - dev: false - - /memoize-one@6.0.0: - resolution: - { - integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==, - } - dev: false - - /memoizee@0.4.15: - resolution: - { - integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==, - } - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-weak-map: 2.0.3 - event-emitter: 0.3.5 - is-promise: 2.2.2 - lru-queue: 0.1.0 - next-tick: 1.1.0 - timers-ext: 0.1.7 - dev: false - - /memory-pager@1.5.0: - resolution: - { - integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==, - } - requiresBuild: true - dev: false - optional: true - /merge2@1.4.1: - resolution: - { - integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, - } - engines: { node: '>= 8' } - - /micromatch@4.0.5: - resolution: - { - integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==, - } - engines: { node: '>=8.6' } - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color - /mimic-fn@2.1.0: - resolution: - { - integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, - } - engines: { node: '>=6' } - dev: false - - /mimic-fn@3.1.0: - resolution: - { - integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==, - } - engines: { node: '>=8' } - dev: false - - /mimic-response@3.1.0: - resolution: - { - integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==, - } - engines: { node: '>=10' } - dev: false - - /minimatch@3.1.2: - resolution: - { - integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, - } - dependencies: - brace-expansion: 1.1.11 - dev: false - - /minimatch@5.1.6: - resolution: - { - integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==, - } - engines: { node: '>=10' } - dependencies: - brace-expansion: 2.0.1 - dev: false - - /minimatch@9.0.4: - resolution: - { - integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==, - } - engines: { node: '>=16 || 14 >=14.17' } - dependencies: - brace-expansion: 2.0.1 - - /minimist@1.2.8: - resolution: - { - integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, - } - dev: false - - /minipass@7.0.4: - resolution: - { - integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==, - } - engines: { node: '>=16 || 14 >=14.17' } - - /mkdirp-classic@0.5.3: - resolution: - { - integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==, - } - dev: false - - /mkdirp@1.0.4: - resolution: - { - integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==, - } - engines: { node: '>=10' } - hasBin: true - dev: false - - /monaco-editor@0.38.0: - resolution: - { - integrity: sha512-11Fkh6yzEmwx7O0YoLxeae0qEGFwmyPRlVxpg7oF9czOOCB/iCjdJrG5I67da5WiXK3YJCxoz9TJFE8Tfq/v9A==, - } - dev: false - - /monaco-editor@0.48.0: - resolution: - { - integrity: sha512-goSDElNqFfw7iDHMg8WDATkfcyeLTNpBHQpO8incK6p5qZt5G/1j41X0xdGzpIkGojGXM+QiRQyLjnfDVvrpwA==, - } - dev: false - - /mongodb-connection-string-url@2.6.0: - resolution: - { - integrity: sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==, - } - dependencies: - '@types/whatwg-url': 8.2.2 - whatwg-url: 11.0.0 - dev: false - - /mongodb@4.17.1: - resolution: - { - integrity: sha512-MBuyYiPUPRTqfH2dV0ya4dcr2E5N52ocBuZ8Sgg/M030nGF78v855B3Z27mZJnp8PxjnUquEnAtjOsphgMZOlQ==, - } - engines: { node: '>=12.9.0' } - dependencies: - bson: 4.7.2 - mongodb-connection-string-url: 2.6.0 - socks: 2.8.3 - optionalDependencies: - '@aws-sdk/credential-providers': 3.564.0 - '@mongodb-js/saslprep': 1.1.5 + mdast-util-mdx-jsx@3.1.3: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.2 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.0.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + memoize-one@6.0.0: {} + + memory-pager@1.5.0: {} + + merge2@1.4.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.1: + dependencies: + '@types/acorn': 4.0.6 + '@types/estree': 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.2.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 transitivePeerDependencies: - - aws-crt - dev: false - - /mongoose-paginate-v2@1.7.22: - resolution: - { - integrity: sha512-xW5GugkE21DJiu9e13EOxKt4ejEKQkRP/S1PkkXRjnk2rRZVKBcld1nPV+VJ/YCPfm8hb3sz9OvI7O38RmixkA==, - } - engines: { node: '>=4.0.0' } - dev: false - - /mongoose@6.12.3: - resolution: - { - integrity: sha512-MNJymaaXali7w7rHBxVUoQ3HzHHMk/7I/+yeeoSa4rUzdjZwIWQznBNvVgc0A8ghuJwsuIkb5LyLV6gSjGjWyQ==, - } - engines: { node: '>=12.0.0' } - dependencies: - bson: 4.7.2 - kareem: 2.5.1 - mongodb: 4.17.1 + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mimic-response@3.1.0: {} + + minimist@1.2.8: {} + + mkdirp-classic@0.5.3: {} + + monaco-editor@0.55.1: + dependencies: + dompurify: 3.2.7 + marked: 14.0.0 + + mongodb-connection-string-url@3.0.2: + dependencies: + '@types/whatwg-url': 11.0.5 + whatwg-url: 14.2.0 + + mongodb@6.10.0: + dependencies: + '@mongodb-js/saslprep': 1.4.0 + bson: 6.10.4 + mongodb-connection-string-url: 3.0.2 + + mongoose-aggregate-paginate-v2@1.1.2: {} + + mongoose-paginate-v2@1.8.5: {} + + mongoose@8.8.1: + dependencies: + bson: 6.10.4 + kareem: 2.6.3 + mongodb: 6.10.0 mpath: 0.9.0 - mquery: 4.0.3 + mquery: 5.0.0 ms: 2.1.3 - sift: 16.0.1 + sift: 17.1.3 transitivePeerDependencies: - - aws-crt + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks - supports-color - dev: false - - /mpath@0.9.0: - resolution: - { - integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==, - } - engines: { node: '>=4.0.0' } - dev: false - - /mquery@4.0.3: - resolution: - { - integrity: sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==, - } - engines: { node: '>=12.0.0' } - dependencies: - debug: 4.3.4 + + mpath@0.9.0: {} + + mquery@5.0.0: + dependencies: + debug: 4.4.3 transitivePeerDependencies: - supports-color - dev: false - - /ms@2.1.2: - resolution: - { - integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, - } - dev: false - - /ms@2.1.3: - resolution: - { - integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, - } - dev: false - - /mz@2.7.0: - resolution: - { - integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, - } + + ms@2.1.3: {} + + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - /nanoid@3.3.7: - resolution: - { - integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==, - } - engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } - hasBin: true + nanoid@3.3.11: {} - /napi-build-utils@1.0.2: - resolution: - { - integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==, - } - dev: false - - /next-tick@1.1.0: - resolution: - { - integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==, - } - dev: false - - /next@14.3.0-canary.7(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-loPrWTCvHvZgOy3rgL9+2WpxNDxlRNt462ihqm/DUuyK8LUZV1F4H920YTAu1wEiYC8RrpNUbpz8K7KRYAkQiA==, - } - engines: { node: '>=18.17.0' } - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - sass: - optional: true + napi-build-utils@2.0.0: {} + + next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): dependencies: - '@next/env': 14.3.0-canary.7 - '@swc/helpers': 0.5.5 - busboy: 1.6.0 - caniuse-lite: 1.0.30001613 - graceful-fs: 4.2.11 + '@next/env': 15.5.8 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001760 postcss: 8.4.31 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.1(react@18.3.1) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + styled-jsx: 5.1.6(react@19.2.2) optionalDependencies: - '@next/swc-darwin-arm64': 14.3.0-canary.7 - '@next/swc-darwin-x64': 14.3.0-canary.7 - '@next/swc-linux-arm64-gnu': 14.3.0-canary.7 - '@next/swc-linux-arm64-musl': 14.3.0-canary.7 - '@next/swc-linux-x64-gnu': 14.3.0-canary.7 - '@next/swc-linux-x64-musl': 14.3.0-canary.7 - '@next/swc-win32-arm64-msvc': 14.3.0-canary.7 - '@next/swc-win32-ia32-msvc': 14.3.0-canary.7 - '@next/swc-win32-x64-msvc': 14.3.0-canary.7 + '@next/swc-darwin-arm64': 15.5.7 + '@next/swc-darwin-x64': 15.5.7 + '@next/swc-linux-arm64-gnu': 15.5.7 + '@next/swc-linux-arm64-musl': 15.5.7 + '@next/swc-linux-x64-gnu': 15.5.7 + '@next/swc-linux-x64-musl': 15.5.7 + '@next/swc-win32-arm64-msvc': 15.5.7 + '@next/swc-win32-x64-msvc': 15.5.7 + sass: 1.77.4 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - dev: false - - /node-abi@3.62.0: - resolution: - { - integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==, - } - engines: { node: '>=10' } - dependencies: - semver: 7.6.0 - dev: false - - /node-addon-api@6.1.0: - resolution: - { - integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==, - } - dev: false - - /node-releases@2.0.14: - resolution: - { - integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==, - } - dev: true - - /normalize-path@3.0.0: - resolution: - { - integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, - } - engines: { node: '>=0.10.0' } - - /normalize-range@0.1.2: - resolution: - { - integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==, - } - engines: { node: '>=0.10.0' } - dev: true - - /object-assign@4.1.1: - resolution: - { - integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, - } - engines: { node: '>=0.10.0' } - - /object-hash@3.0.0: - resolution: - { - integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==, - } - engines: { node: '>= 6' } - - /object-inspect@1.13.1: - resolution: - { - integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==, - } - dev: false - - /object-is@1.1.6: - resolution: - { - integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - dev: false - - /object-keys@1.1.1: - resolution: - { - integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, - } - engines: { node: '>= 0.4' } - dev: false - - /object-to-formdata@4.5.1: - resolution: - { - integrity: sha512-QiM9D0NiU5jV6J6tjE1g7b4Z2tcUnKs1OPUi4iMb2zH+7jwlcUrASghgkFk9GtzqNNq8rTQJtT8AzjBAvLoNMw==, - } - dev: false - - /object.assign@4.1.5: - resolution: - { - integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - has-symbols: 1.0.3 - object-keys: 1.1.1 - dev: false - - /on-exit-leak-free@2.1.2: - resolution: - { - integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==, - } - engines: { node: '>=14.0.0' } - dev: false - - /once@1.4.0: - resolution: - { - integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==, - } + + node-abi@3.85.0: + dependencies: + semver: 7.7.3 + + node-addon-api@6.1.0: {} + + node-releases@2.0.27: {} + + normalize-path@3.0.0: {} + + normalize-range@0.1.2: {} + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + object-to-formdata@4.5.1: {} + + on-exit-leak-free@2.1.2: {} + + once@1.4.0: dependencies: wrappy: 1.0.2 - dev: false - - /onetime@5.1.2: - resolution: - { - integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, - } - engines: { node: '>=6' } - dependencies: - mimic-fn: 2.1.0 - dev: false - - /p-limit@2.3.0: - resolution: - { - integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==, - } - engines: { node: '>=6' } - dependencies: - p-try: 2.2.0 - dev: false - - /p-locate@3.0.0: - resolution: - { - integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==, - } - engines: { node: '>=6' } - dependencies: - p-limit: 2.3.0 - dev: false - - /p-locate@4.1.0: - resolution: - { - integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==, - } - engines: { node: '>=8' } - dependencies: - p-limit: 2.3.0 - dev: false - - /p-try@2.2.0: - resolution: - { - integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==, - } - engines: { node: '>=6' } - dev: false - - /parent-module@1.0.1: - resolution: - { - integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, - } - engines: { node: '>=6' } + + parent-module@1.0.1: dependencies: callsites: 3.1.0 - dev: false - /parse-json@5.2.0: - resolution: - { - integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==, - } - engines: { node: '>=8' } + parse-entities@4.0.2: dependencies: - '@babel/code-frame': 7.24.2 - error-ex: 1.3.2 + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.2.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - dev: false - - /path-exists@3.0.0: - resolution: - { - integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==, - } - engines: { node: '>=4' } - dev: false - - /path-exists@4.0.0: - resolution: - { - integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, - } - engines: { node: '>=8' } - dev: false - - /path-is-absolute@1.0.1: - resolution: - { - integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==, - } - engines: { node: '>=0.10.0' } - dev: false - - /path-key@3.1.1: - resolution: - { - integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, - } - engines: { node: '>=8' } - - /path-parse@1.0.7: - resolution: - { - integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, - } - - /path-scurry@1.10.2: - resolution: - { - integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==, - } - engines: { node: '>=16 || 14 >=14.17' } - dependencies: - lru-cache: 10.2.1 - minipass: 7.0.4 - - /path-to-regexp@6.2.2: - resolution: - { - integrity: sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==, - } - dev: false - - /path-type@4.0.0: - resolution: - { - integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, - } - engines: { node: '>=8' } - dev: false - - /payload@3.0.0-beta.19(@swc/core@1.4.17)(@swc/types@0.1.6)(graphql@16.8.1): - resolution: - { - integrity: sha512-sZvLUa8gO5CEODn8FDM+CZ9RUbRJxM1LAa8Do/MSBZ+XSd242rCad4Zk1qd8CBFwTcBMCG7ISfOAt/uxgzjyaQ==, - } - engines: { node: '>=18.20.2' } - hasBin: true - peerDependencies: - '@swc/core': ^1.4.13 - graphql: ^16.8.1 - peerDependenciesMeta: - '@swc/core': - optional: true + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-to-regexp@6.3.0: {} + + path-type@4.0.0: {} + + payload@3.0.0-beta.135(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3): dependencies: - '@payloadcms/translations': 3.0.0-beta.19 - '@swc-node/core': 1.13.0(@swc/core@1.4.17)(@swc/types@0.1.6) - '@swc-node/sourcemap-support': 0.5.0 - '@swc/core': 1.4.17 - '@types/probe-image-size': 7.2.4 - ajv: 8.12.0 + '@monaco-editor/react': 4.6.0(monaco-editor@0.55.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@next/env': 15.5.8 + '@payloadcms/translations': 3.0.0-beta.135 + '@types/busboy': 1.5.4 + ajv: 8.17.1 bson-objectid: 2.0.4 - ci-info: 4.0.0 - conf: 10.2.0 - console-table-printer: 2.11.2 + ci-info: 4.3.1 + console-table-printer: 2.12.1 + croner: 9.0.0 dataloader: 2.2.2 deepmerge: 4.3.1 - dotenv: 8.6.0 - file-type: 16.5.4 - find-up: 4.1.0 - get-tsconfig: 4.7.3 - graphql: 16.8.1 + file-type: 19.3.0 + get-tsconfig: 4.8.1 + graphql: 16.12.0 http-status: 1.6.2 - image-size: 1.1.1 - joi: 17.13.0 - json-schema-to-typescript: 11.0.3 - jsonwebtoken: 9.0.1 + image-size: 1.2.1 + jose: 5.9.6 + json-schema-to-typescript: 15.0.3 minimist: 1.2.8 - mkdirp: 1.0.4 - monaco-editor: 0.38.0 - pino: 8.15.0 - pino-pretty: 10.2.0 + pino: 9.5.0 + pino-pretty: 13.0.0 pluralize: 8.0.0 sanitize-filename: 1.6.3 - scheduler: 0.23.0 scmp: 2.1.0 - uuid: 9.0.1 + ts-essentials: 10.0.3(typescript@5.9.3) + tsx: 4.19.2 + uuid: 10.0.0 + ws: 8.18.3 transitivePeerDependencies: - - '@swc/types' - dev: false - - /peek-readable@4.1.0: - resolution: - { - integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==, - } - engines: { node: '>=8' } - dev: false - - /picocolors@1.0.0: - resolution: - { - integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==, - } - - /picomatch@2.3.1: - resolution: - { - integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, - } - engines: { node: '>=8.6' } - - /pify@2.3.0: - resolution: - { - integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==, - } - engines: { node: '>=0.10.0' } - - /pino-abstract-transport@1.0.0: - resolution: - { - integrity: sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==, - } - dependencies: - readable-stream: 4.5.2 - split2: 4.2.0 - dev: false + - bufferutil + - monaco-editor + - react + - react-dom + - typescript + - utf-8-validate + + peek-readable@5.4.2: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pify@2.3.0: {} - /pino-abstract-transport@1.2.0: - resolution: - { - integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==, - } + pino-abstract-transport@2.0.0: dependencies: - readable-stream: 4.5.2 split2: 4.2.0 - dev: false - /pino-pretty@10.2.0: - resolution: - { - integrity: sha512-tRvpyEmGtc2D+Lr3FulIZ+R1baggQ4S3xD2Ar93KixFEDx6SEAUP3W5aYuEw1C73d6ROrNcB2IXLteW8itlwhA==, - } - hasBin: true + pino-pretty@13.0.0: dependencies: colorette: 2.0.20 dateformat: 4.6.3 fast-copy: 3.0.2 fast-safe-stringify: 2.1.1 - help-me: 4.2.0 + help-me: 5.0.0 joycon: 3.1.1 minimist: 1.2.8 on-exit-leak-free: 2.1.2 - pino-abstract-transport: 1.2.0 - pump: 3.0.0 - readable-stream: 4.5.2 + pino-abstract-transport: 2.0.0 + pump: 3.0.3 secure-json-parse: 2.7.0 - sonic-boom: 3.8.1 + sonic-boom: 4.2.0 strip-json-comments: 3.1.1 - dev: false - - /pino-std-serializers@6.2.2: - resolution: - { - integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==, - } - dev: false - - /pino@8.15.0: - resolution: - { - integrity: sha512-olUADJByk4twxccmAxb1RiGKOSvddHugCV3wkqjyv+3Sooa2KLrmXrKEWOKi0XPCLasRR5jBXxioE1jxUa4KzQ==, - } - hasBin: true + + pino-std-serializers@7.0.0: {} + + pino@9.5.0: dependencies: atomic-sleep: 1.0.0 fast-redact: 3.5.0 on-exit-leak-free: 2.1.2 - pino-abstract-transport: 1.0.0 - pino-std-serializers: 6.2.2 - process-warning: 2.3.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 4.0.1 quick-format-unescaped: 4.0.4 real-require: 0.2.0 - safe-stable-stringify: 2.4.3 - sonic-boom: 3.8.1 - thread-stream: 2.7.0 - dev: false - - /pirates@4.0.6: - resolution: - { - integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==, - } - engines: { node: '>= 6' } - - /pkg-up@3.1.0: - resolution: - { - integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==, - } - engines: { node: '>=8' } - dependencies: - find-up: 3.0.0 - dev: false - - /pluralize@8.0.0: - resolution: - { - integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==, - } - engines: { node: '>=4' } - dev: false - - /possible-typed-array-names@1.0.0: - resolution: - { - integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==, - } - engines: { node: '>= 0.4' } - dev: false - - /postcss-import@15.1.0(postcss@8.4.38): - resolution: - { - integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==, - } - engines: { node: '>=14.0.0' } - peerDependencies: - postcss: ^8.0.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + + pirates@4.0.7: {} + + pluralize@8.0.0: {} + + postcss-import@15.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.38 + postcss: 8.5.6 postcss-value-parser: 4.2.0 read-cache: 1.0.0 - resolve: 1.22.8 - - /postcss-js@4.0.1(postcss@8.4.38): - resolution: - { - integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==, - } - engines: { node: ^12 || ^14 || >= 16 } - peerDependencies: - postcss: ^8.4.21 + resolve: 1.22.11 + + postcss-js@4.1.0(postcss@8.5.6): dependencies: camelcase-css: 2.0.1 - postcss: 8.4.38 - - /postcss-load-config@4.0.2(postcss@8.4.38): - resolution: - { - integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==, - } - engines: { node: '>= 14' } - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true + postcss: 8.5.6 + + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0): dependencies: - lilconfig: 3.1.1 - postcss: 8.4.38 - yaml: 2.4.2 + lilconfig: 3.1.3 + optionalDependencies: + jiti: 1.21.7 + postcss: 8.5.6 + tsx: 4.21.0 - /postcss-nested@6.0.1(postcss@8.4.38): - resolution: - { - integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==, - } - engines: { node: '>=12.0' } - peerDependencies: - postcss: ^8.2.14 + postcss-nested@6.2.0(postcss@8.5.6): dependencies: - postcss: 8.4.38 - postcss-selector-parser: 6.0.16 + postcss: 8.5.6 + postcss-selector-parser: 6.1.2 - /postcss-selector-parser@6.0.16: - resolution: - { - integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==, - } - engines: { node: '>=4' } + postcss-selector-parser@6.1.2: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - /postcss-value-parser@4.2.0: - resolution: - { - integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==, - } - - /postcss@8.4.31: - resolution: - { - integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==, - } - engines: { node: ^10 || ^12 || >=14 } - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.2.0 - dev: false - - /postcss@8.4.38: - resolution: - { - integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==, - } - engines: { node: ^10 || ^12 || >=14 } - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.2.0 - - /prebuild-install@7.1.2: - resolution: - { - integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==, - } - engines: { node: '>=10' } - hasBin: true + postcss-value-parser@4.2.0: {} + + postcss@8.4.31: dependencies: - detect-libc: 2.0.3 + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 expand-template: 2.0.3 github-from-package: 0.0.0 minimist: 1.2.8 mkdirp-classic: 0.5.3 - napi-build-utils: 1.0.2 - node-abi: 3.62.0 - pump: 3.0.0 + napi-build-utils: 2.0.0 + node-abi: 3.85.0 + pump: 3.0.3 rc: 1.2.8 simple-get: 4.0.1 - tar-fs: 2.1.1 + tar-fs: 2.1.4 tunnel-agent: 0.6.0 - dev: false - - /prettier@2.8.8: - resolution: - { - integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==, - } - engines: { node: '>=10.13.0' } - hasBin: true - dev: false - - /prismjs@1.29.0: - resolution: - { - integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==, - } - engines: { node: '>=6' } - dev: false - - /process-warning@2.3.2: - resolution: - { - integrity: sha512-n9wh8tvBe5sFmsqlg+XQhaQLumwpqoAUruLwjCopgTmUBjJ/fjtBsJzKleCaIGBOMXYEhp1YfKl4d7rJ5ZKJGA==, - } - dev: false - - /process@0.11.10: - resolution: - { - integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==, - } - engines: { node: '>= 0.6.0' } - dev: false - - /prompts@2.4.2: - resolution: - { - integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==, - } - engines: { node: '>= 6' } + + prettier@3.7.4: {} + + prismjs@1.30.0: {} + + process-warning@4.0.1: {} + + prompts@2.4.2: dependencies: kleur: 3.0.3 sisteransi: 1.0.5 - dev: false - /prop-types@15.8.1: - resolution: - { - integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==, - } + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 - dev: false - /pump@3.0.0: - resolution: - { - integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==, - } + pump@3.0.3: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 - dev: false - - /punycode@2.3.1: - resolution: - { - integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, - } - engines: { node: '>=6' } - dev: false - - /qs@6.11.2: - resolution: - { - integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==, - } - engines: { node: '>=0.6' } - dependencies: - side-channel: 1.0.6 - dev: false - - /qs@6.12.1: - resolution: - { - integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==, - } - engines: { node: '>=0.6' } - dependencies: - side-channel: 1.0.6 - dev: false - - /queue-microtask@1.2.3: - resolution: - { - integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, - } - - /queue-tick@1.0.1: - resolution: - { - integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==, - } - dev: false - - /queue@6.0.2: - resolution: - { - integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==, - } + + punycode@2.3.1: {} + + qs-esm@7.0.2: {} + + queue-microtask@1.2.3: {} + + queue@6.0.2: dependencies: inherits: 2.0.4 - dev: false - - /quick-format-unescaped@4.0.4: - resolution: - { - integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==, - } - dev: false - - /rc@1.2.8: - resolution: - { - integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==, - } - hasBin: true + + quick-format-unescaped@4.0.4: {} + + rc@1.2.8: dependencies: deep-extend: 0.6.0 ini: 1.3.8 minimist: 1.2.8 strip-json-comments: 2.0.1 - dev: false - - /react-animate-height@2.1.2(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-A9jfz/4CTdsIsE7WCQtO9UkOpMBcBRh8LxyHl2eoZz1ki02jpyUL5xt58gabd0CyeLQ8fRyQ+s2lyV2Ufu8Owg==, - } - engines: { node: '>= 6.0.0' } - peerDependencies: - react: '>=15.6.2' - react-dom: '>=15.6.2' + + react-animate-height@2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: classnames: 2.5.1 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /react-datepicker@6.2.0(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-GzEOiE6yLfp9P6XNkOhXuYtZHzoAx3tirbi7/dj2WHlGM+NGE1lefceqGR0ZrYsYaqsNJhIJFTgwUpzVzA+mjw==, - } - peerDependencies: - react: ^16.9.0 || ^17 || ^18 - react-dom: ^16.9.0 || ^17 || ^18 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + react-datepicker@6.9.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - '@floating-ui/react': 0.26.13(react-dom@18.3.1)(react@18.3.1) - classnames: 2.5.1 - date-fns: 3.3.1 + '@floating-ui/react': 0.26.28(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + clsx: 2.1.1 + date-fns: 3.6.0 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-onclickoutside: 6.13.0(react-dom@18.3.1)(react@18.3.1) - dev: false - - /react-diff-viewer-continued@3.2.6(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-GrzyqQnjIMoej+jMjWvtVSsQqhXgzEGqpXlJ2dAGfOk7Q26qcm8Gu6xtI430PBUyZsERe8BJSQf+7VZZo8IBNQ==, - } - engines: { node: '>= 8' } - peerDependencies: - react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-onclickoutside: 6.13.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + + react-diff-viewer-continued@3.2.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - '@emotion/css': 11.11.2 + '@emotion/css': 11.13.5 classnames: 2.5.1 diff: 5.2.0 memoize-one: 6.0.0 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /react-dom@18.3.1(react@18.3.1): - resolution: - { - integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==, - } - peerDependencies: - react: ^18.3.1 + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + transitivePeerDependencies: + - supports-color + + react-dom@19.2.2(react@19.2.2): dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 - dev: false - - /react-error-boundary@3.1.4(react@18.3.1): - resolution: - { - integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==, - } - engines: { node: '>=10', npm: '>=6' } - peerDependencies: - react: '>=16.13.1' + react: 19.2.2 + scheduler: 0.27.0 + + react-error-boundary@3.1.4(react@19.2.2): dependencies: - '@babel/runtime': 7.24.4 - react: 18.3.1 - dev: false + '@babel/runtime': 7.28.4 + react: 19.2.2 - /react-error-boundary@4.0.12(react@18.3.1): - resolution: - { - integrity: sha512-kJdxdEYlb7CPC1A0SeUY38cHpjuu6UkvzKiAmqmOFL21VRfMhOcWxTCBgLVCO0VEMh9JhFNcVaXlV4/BTpiwOA==, - } - peerDependencies: - react: '>=16.13.1' + react-error-boundary@4.0.13(react@19.2.2): dependencies: - '@babel/runtime': 7.24.4 - react: 18.3.1 - dev: false + '@babel/runtime': 7.28.4 + react: 19.2.2 - /react-image-crop@10.1.8(react@18.3.1): - resolution: - { - integrity: sha512-4rb8XtXNx7ZaOZarKKnckgz4xLMvds/YrU6mpJfGhGAsy2Mg4mIw1x+DCCGngVGq2soTBVVOxx2s/C6mTX9+pA==, - } - peerDependencies: - react: '>=16.13.1' + react-image-crop@10.1.8(react@19.2.2): dependencies: - react: 18.3.1 - dev: false - - /react-is@16.13.1: - resolution: - { - integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, - } - dev: false - - /react-onclickoutside@6.13.0(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A==, - } - peerDependencies: - react: ^15.5.x || ^16.x || ^17.x || ^18.x - react-dom: ^15.5.x || ^16.x || ^17.x || ^18.x + react: 19.2.2 + + react-is@16.13.1: {} + + react-onclickoutside@6.13.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - /react-select@5.7.4(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-NhuE56X+p9QDFh4BgeygHFIvJJszO1i1KSkg/JPcIJrbovyRtI+GuOEa4XzFCEpZRAEoEI8u/cAHK+jG/PgUzQ==, - } - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-select@5.8.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - '@babel/runtime': 7.24.4 - '@emotion/cache': 11.11.0 - '@emotion/react': 11.11.4(@types/react@18.3.1)(react@18.3.1) - '@floating-ui/dom': 1.6.4 - '@types/react-transition-group': 4.4.10 + '@babel/runtime': 7.28.4 + '@emotion/cache': 11.14.0 + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.2) + '@floating-ui/dom': 1.7.4 + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) memoize-one: 6.0.0 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-transition-group: 4.4.5(react-dom@18.3.1)(react@18.3.1) - use-isomorphic-layout-effect: 1.1.2(@types/react@18.3.1)(react@18.3.1) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + use-isomorphic-layout-effect: 1.2.1(@types/react@19.2.1)(react@19.2.2) transitivePeerDependencies: - '@types/react' - dev: false + - supports-color - /react-toastify@10.0.4(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-etR3RgueY8pe88SA67wLm8rJmL1h+CLqUGHuAoNsseW35oTGJEri6eBTyaXnFKNQ80v/eO10hBYLgz036XRGgA==, - } - peerDependencies: - react: '>=16' - react-dom: '>=16' - dependencies: - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /react-toastify@8.2.0(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-Pg2Ju7NngAamarFvLwqrFomJ57u/Ay6i6zfLurt/qPynWkAkOthu6vxfqYpJCyNhHRhR4hu7+bySSeWWJu6PAg==, - } - peerDependencies: - react: '>=16' - react-dom: '>=16' - dependencies: - clsx: 1.2.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /react-transition-group@4.4.5(react-dom@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==, - } - peerDependencies: - react: '>=16.6.0' - react-dom: '>=16.6.0' + react-transition-group@4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.28.4 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - /react@18.3.1: - resolution: - { - integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==, - } - engines: { node: '>=0.10.0' } - dependencies: - loose-envify: 1.4.0 - dev: false + react@19.2.2: {} - /read-cache@1.0.0: - resolution: - { - integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==, - } + read-cache@1.0.0: dependencies: pify: 2.3.0 - /readable-stream@3.6.2: - resolution: - { - integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==, - } - engines: { node: '>= 6' } + readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - dev: false - - /readable-stream@4.5.2: - resolution: - { - integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==, - } - engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - dev: false - - /readable-web-to-node-stream@3.0.2: - resolution: - { - integrity: sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==, - } - engines: { node: '>=8' } - dependencies: - readable-stream: 3.6.2 - dev: false - /readdirp@3.6.0: - resolution: - { - integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, - } - engines: { node: '>=8.10.0' } + readdirp@3.6.0: dependencies: picomatch: 2.3.1 - /real-require@0.2.0: - resolution: - { - integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==, - } - engines: { node: '>= 12.13.0' } - dev: false - - /regenerator-runtime@0.14.1: - resolution: - { - integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==, - } - dev: false - - /regexp.prototype.flags@1.5.2: - resolution: - { - integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-errors: 1.3.0 - set-function-name: 2.0.2 - dev: false - - /require-from-string@2.0.2: - resolution: - { - integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==, - } - engines: { node: '>=0.10.0' } - dev: false - - /resolve-from@4.0.0: - resolution: - { - integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, - } - engines: { node: '>=4' } - dev: false - - /resolve-pkg-maps@1.0.0: - resolution: - { - integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==, - } - - /resolve@1.22.8: - resolution: - { - integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==, - } - hasBin: true + real-require@0.2.0: {} + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.11: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - /reusify@1.0.4: - resolution: - { - integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==, - } - engines: { iojs: '>=1.0.0', node: '>=0.10.0' } + reusify@1.1.0: {} - /run-parallel@1.2.0: - resolution: - { - integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, - } + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - /safe-buffer@5.2.1: - resolution: - { - integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==, - } - dev: false - - /safe-stable-stringify@2.4.3: - resolution: - { - integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==, - } - engines: { node: '>=10' } - dev: false - - /sanitize-filename@1.6.3: - resolution: - { - integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==, - } + safe-buffer@5.2.1: {} + + safe-stable-stringify@2.5.0: {} + + sanitize-filename@1.6.3: dependencies: truncate-utf8-bytes: 1.0.2 - dev: false - - /sass@1.75.0: - resolution: - { - integrity: sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw==, - } - engines: { node: '>=14.0.0' } - hasBin: true + + sass@1.77.4: dependencies: chokidar: 3.6.0 - immutable: 4.3.5 - source-map-js: 1.2.0 - dev: false + immutable: 4.3.7 + source-map-js: 1.2.1 - /scheduler@0.23.0: - resolution: - { - integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==, - } - dependencies: - loose-envify: 1.4.0 - dev: false + scheduler@0.0.0-experimental-3edc000d-20240926: {} - /scheduler@0.23.2: - resolution: - { - integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==, - } - dependencies: - loose-envify: 1.4.0 - dev: false - - /scmp@2.1.0: - resolution: - { - integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==, - } - dev: false - - /secure-json-parse@2.7.0: - resolution: - { - integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==, - } - dev: false - - /semver@7.6.0: - resolution: - { - integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==, - } - engines: { node: '>=10' } - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: false + scheduler@0.27.0: {} - /set-function-length@1.2.2: - resolution: - { - integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==, - } - engines: { node: '>= 0.4' } - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 - has-property-descriptors: 1.0.2 - dev: false - - /set-function-name@2.0.2: - resolution: - { - integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==, - } - engines: { node: '>= 0.4' } - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - dev: false - - /sharp@0.32.6: - resolution: - { - integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==, - } - engines: { node: '>=14.15.0' } - requiresBuild: true + scmp@2.1.0: {} + + secure-json-parse@2.7.0: {} + + semver@7.7.3: {} + + sharp@0.32.6: dependencies: color: 4.2.3 - detect-libc: 2.0.3 + detect-libc: 2.1.2 node-addon-api: 6.1.0 - prebuild-install: 7.1.2 - semver: 7.6.0 + prebuild-install: 7.1.3 + semver: 7.7.3 simple-get: 4.0.1 - tar-fs: 3.0.6 + tar-fs: 3.1.1 tunnel-agent: 0.6.0 - dev: false + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a + + sharp@0.34.5: + dependencies: + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true - /shebang-command@2.0.0: - resolution: - { - integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, - } - engines: { node: '>=8' } + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - /shebang-regex@3.0.0: - resolution: - { - integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, - } - engines: { node: '>=8' } - - /side-channel@1.0.6: - resolution: - { - integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==, - } - engines: { node: '>= 0.4' } - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.1 - dev: false - - /sift@16.0.1: - resolution: - { - integrity: sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==, - } - dev: false - - /signal-exit@4.1.0: - resolution: - { - integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, - } - engines: { node: '>=14' } - - /simple-concat@1.0.1: - resolution: - { - integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==, - } - dev: false - - /simple-get@4.0.1: - resolution: - { - integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==, - } + shebang-regex@3.0.0: {} + + sift@17.1.3: {} + + simple-concat@1.0.1: {} + + simple-get@4.0.1: dependencies: decompress-response: 6.0.0 once: 1.4.0 simple-concat: 1.0.1 - dev: false - - /simple-swizzle@0.2.2: - resolution: - { - integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==, - } - dependencies: - is-arrayish: 0.3.2 - dev: false - - /simple-wcswidth@1.0.1: - resolution: - { - integrity: sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==, - } - dev: false - - /sisteransi@1.0.5: - resolution: - { - integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==, - } - dev: false - - /smart-buffer@4.2.0: - resolution: - { - integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==, - } - engines: { node: '>= 6.0.0', npm: '>= 3.0.0' } - dev: false - - /socks@2.8.3: - resolution: - { - integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==, - } - engines: { node: '>= 10.0.0', npm: '>= 3.0.0' } - dependencies: - ip-address: 9.0.5 - smart-buffer: 4.2.0 - dev: false - - /sonic-boom@3.8.1: - resolution: - { - integrity: sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==, - } + + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + + simple-wcswidth@1.1.2: {} + + sisteransi@1.0.5: {} + + sonic-boom@4.2.0: dependencies: atomic-sleep: 1.0.0 - dev: false - - /source-map-js@1.2.0: - resolution: - { - integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==, - } - engines: { node: '>=0.10.0' } - - /source-map-support@0.5.21: - resolution: - { - integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, - } - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: false - - /source-map@0.5.7: - resolution: - { - integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==, - } - engines: { node: '>=0.10.0' } - dev: false - - /source-map@0.6.1: - resolution: - { - integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, - } - engines: { node: '>=0.10.0' } - dev: false - - /sparse-bitfield@3.0.3: - resolution: - { - integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==, - } - requiresBuild: true + + sonner@1.7.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2): + dependencies: + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + + source-map-js@1.2.1: {} + + source-map@0.5.7: {} + + sparse-bitfield@3.0.3: dependencies: memory-pager: 1.5.0 - dev: false - optional: true - /split2@4.2.0: - resolution: - { - integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==, - } - engines: { node: '>= 10.x' } - dev: false - - /sprintf-js@1.1.3: - resolution: - { - integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==, - } - dev: false - - /state-local@1.0.7: - resolution: - { - integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==, - } - dev: false - - /stop-iteration-iterator@1.0.0: - resolution: - { - integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==, - } - engines: { node: '>= 0.4' } - dependencies: - internal-slot: 1.0.7 - dev: false - - /streamsearch@1.1.0: - resolution: - { - integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==, - } - engines: { node: '>=10.0.0' } - dev: false - - /streamx@2.16.1: - resolution: - { - integrity: sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==, - } + split2@4.2.0: {} + + state-local@1.0.7: {} + + streamsearch@1.1.0: {} + + streamx@2.23.0: dependencies: + events-universal: 1.0.1 fast-fifo: 1.3.2 - queue-tick: 1.0.1 - optionalDependencies: - bare-events: 2.2.2 - dev: false - - /string-width@4.2.3: - resolution: - { - integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, - } - engines: { node: '>=8' } - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - /string-width@5.1.2: - resolution: - { - integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==, - } - engines: { node: '>=12' } - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - /string_decoder@1.3.0: - resolution: - { - integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==, - } + text-decoder: 1.2.3 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - dev: false - - /strip-ansi@6.0.1: - resolution: - { - integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, - } - engines: { node: '>=8' } - dependencies: - ansi-regex: 5.0.1 - - /strip-ansi@7.1.0: - resolution: - { - integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==, - } - engines: { node: '>=12' } - dependencies: - ansi-regex: 6.0.1 - - /strip-json-comments@2.0.1: - resolution: - { - integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==, - } - engines: { node: '>=0.10.0' } - dev: false - - /strip-json-comments@3.1.1: - resolution: - { - integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, - } - engines: { node: '>=8' } - dev: false - - /strnum@1.0.5: - resolution: - { - integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==, - } - requiresBuild: true - dev: false - optional: true - /strtok3@6.3.0: - resolution: - { - integrity: sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==, - } - engines: { node: '>=10' } + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + strtok3@8.1.0: dependencies: '@tokenizer/token': 0.3.0 - peek-readable: 4.1.0 - dev: false - - /styled-jsx@5.1.1(react@18.3.1): - resolution: - { - integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==, - } - engines: { node: '>= 12.0.0' } - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true + peek-readable: 5.4.2 + + styled-jsx@5.1.6(react@19.2.2): dependencies: client-only: 0.0.1 - react: 18.3.1 - dev: false - - /stylis@4.2.0: - resolution: - { - integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==, - } - dev: false - - /sucrase@3.35.0: - resolution: - { - integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==, - } - engines: { node: '>=16 || 14 >=14.17' } - hasBin: true + react: 19.2.2 + + stylis@4.2.0: {} + + sucrase@3.35.1: dependencies: - '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/gen-mapping': 0.3.13 commander: 4.1.1 - glob: 10.3.12 lines-and-columns: 1.2.4 mz: 2.7.0 - pirates: 4.0.6 + pirates: 4.0.7 + tinyglobby: 0.2.15 ts-interface-checker: 0.1.13 - /supports-color@5.5.0: - resolution: - { - integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, - } - engines: { node: '>=4' } - dependencies: - has-flag: 3.0.0 - dev: false - - /supports-preserve-symlinks-flag@1.0.0: - resolution: - { - integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, - } - engines: { node: '>= 0.4' } - - /tabbable@5.3.3: - resolution: - { - integrity: sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==, - } - dev: false - - /tabbable@6.2.0: - resolution: - { - integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==, - } - dev: false - - /tailwind-merge@2.3.0: - resolution: - { - integrity: sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==, - } - dependencies: - '@babel/runtime': 7.24.4 - dev: false - - /tailwindcss-animate@1.0.7(tailwindcss@3.4.3): - resolution: - { - integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==, - } - peerDependencies: - tailwindcss: '>=3.0.0 || insiders' + supports-preserve-symlinks-flag@1.0.0: {} + + tabbable@6.3.0: {} + + tailwind-merge@2.6.0: {} + + tailwindcss-animate@1.0.7(tailwindcss@3.4.19(tsx@4.21.0)): dependencies: - tailwindcss: 3.4.3 - dev: false + tailwindcss: 3.4.19(tsx@4.21.0) - /tailwindcss@3.4.3: - resolution: - { - integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==, - } - engines: { node: '>=14.0.0' } - hasBin: true + tailwindcss@3.4.19(tsx@4.21.0): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 chokidar: 3.6.0 didyoumean: 1.2.2 dlv: 1.1.3 - fast-glob: 3.3.2 + fast-glob: 3.3.3 glob-parent: 6.0.2 is-glob: 4.0.3 - jiti: 1.21.0 - lilconfig: 2.1.0 - micromatch: 4.0.5 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 normalize-path: 3.0.0 object-hash: 3.0.0 - picocolors: 1.0.0 - postcss: 8.4.38 - postcss-import: 15.1.0(postcss@8.4.38) - postcss-js: 4.0.1(postcss@8.4.38) - postcss-load-config: 4.0.2(postcss@8.4.38) - postcss-nested: 6.0.1(postcss@8.4.38) - postcss-selector-parser: 6.0.16 - resolve: 1.22.8 - sucrase: 3.35.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-import: 15.1.0(postcss@8.5.6) + postcss-js: 4.1.0(postcss@8.5.6) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0) + postcss-nested: 6.2.0(postcss@8.5.6) + postcss-selector-parser: 6.1.2 + resolve: 1.22.11 + sucrase: 3.35.1 transitivePeerDependencies: - - ts-node + - tsx + - yaml - /tar-fs@2.1.1: - resolution: - { - integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==, - } + tar-fs@2.1.4: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.0 + pump: 3.0.3 tar-stream: 2.2.0 - dev: false - /tar-fs@3.0.6: - resolution: - { - integrity: sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==, - } + tar-fs@3.1.1: dependencies: - pump: 3.0.0 + pump: 3.0.3 tar-stream: 3.1.7 optionalDependencies: - bare-fs: 2.3.0 - bare-path: 2.1.2 - dev: false + bare-fs: 4.5.2 + bare-path: 3.0.0 + transitivePeerDependencies: + - bare-abort-controller + - bare-buffer + - react-native-b4a - /tar-stream@2.2.0: - resolution: - { - integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==, - } - engines: { node: '>=6' } + tar-stream@2.2.0: dependencies: bl: 4.1.0 - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 fs-constants: 1.0.0 inherits: 2.0.4 readable-stream: 3.6.2 - dev: false - /tar-stream@3.1.7: - resolution: - { - integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==, - } + tar-stream@3.1.7: dependencies: - b4a: 1.6.6 + b4a: 1.7.3 fast-fifo: 1.3.2 - streamx: 2.16.1 - dev: false + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + text-decoder@1.2.3: + dependencies: + b4a: 1.7.3 + transitivePeerDependencies: + - react-native-b4a - /thenify-all@1.6.0: - resolution: - { - integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, - } - engines: { node: '>=0.8' } + thenify-all@1.6.0: dependencies: thenify: 3.3.1 - /thenify@3.3.1: - resolution: - { - integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, - } + thenify@3.3.1: dependencies: any-promise: 1.3.0 - /thread-stream@2.7.0: - resolution: - { - integrity: sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==, - } + thread-stream@3.1.0: dependencies: real-require: 0.2.0 - dev: false - - /timers-ext@0.1.7: - resolution: - { - integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==, - } - dependencies: - es5-ext: 0.10.64 - next-tick: 1.1.0 - dev: false - - /to-fast-properties@2.0.0: - resolution: - { - integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==, - } - engines: { node: '>=4' } - dev: false - - /to-regex-range@5.0.1: - resolution: - { - integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, - } - engines: { node: '>=8.0' } + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - /token-types@4.2.1: - resolution: - { - integrity: sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==, - } - engines: { node: '>=10' } + token-types@6.1.1: dependencies: + '@borewit/text-codec': 0.1.1 '@tokenizer/token': 0.3.0 ieee754: 1.2.1 - dev: false - /tr46@3.0.0: - resolution: - { - integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==, - } - engines: { node: '>=12' } + tr46@5.1.1: dependencies: punycode: 2.3.1 - dev: false - - /truncate-utf8-bytes@1.0.2: - resolution: - { - integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==, - } - dependencies: - utf8-byte-length: 1.0.4 - dev: false - - /ts-essentials@7.0.3(typescript@5.4.5): - resolution: - { - integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==, - } - peerDependencies: - typescript: '>=3.7.0' - dependencies: - typescript: 5.4.5 - dev: false - - /ts-interface-checker@0.1.13: - resolution: - { - integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==, - } - - /tslib@1.14.1: - resolution: - { - integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==, - } - requiresBuild: true - dev: false - optional: true - /tslib@2.6.2: - resolution: - { - integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==, - } - dev: false - - /tsx@4.7.3: - resolution: - { - integrity: sha512-+fQnMqIp/jxZEXLcj6WzYy9FhcS5/Dfk8y4AtzJ6ejKcKqmfTF8Gso/jtrzDggCF2zTU20gJa6n8XqPYwDAUYQ==, - } - engines: { node: '>=18.0.0' } - hasBin: true + truncate-utf8-bytes@1.0.2: + dependencies: + utf8-byte-length: 1.0.5 + + ts-essentials@10.0.3(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + + ts-interface-checker@0.1.13: {} + + tslib@2.8.1: {} + + tsx@4.19.2: + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.8.1 + optionalDependencies: + fsevents: 2.3.3 + + tsx@4.21.0: dependencies: - esbuild: 0.19.12 - get-tsconfig: 4.7.3 + esbuild: 0.27.1 + get-tsconfig: 4.13.0 optionalDependencies: fsevents: 2.3.3 - dev: true - /tunnel-agent@0.6.0: - resolution: - { - integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==, - } + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 - dev: false - - /type@2.7.2: - resolution: - { - integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==, - } - dev: false - - /typescript@5.4.5: - resolution: - { - integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==, - } - engines: { node: '>=14.17' } - hasBin: true - /undici-types@5.26.5: - resolution: - { - integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==, - } - - /update-browserslist-db@1.0.13(browserslist@4.23.0): - resolution: - { - integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==, - } - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + typescript@5.9.3: {} + + uint8array-extras@1.5.0: {} + + undici-types@6.21.0: {} + + unist-util-is@6.0.1: dependencies: - browserslist: 4.23.0 - escalade: 3.1.2 - picocolors: 1.0.0 - dev: true + '@types/unist': 3.0.3 - /uri-js@4.4.1: - resolution: - { - integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, - } + unist-util-position-from-estree@2.0.0: dependencies: - punycode: 2.3.1 - dev: false + '@types/unist': 3.0.3 - /use-context-selector@1.4.1(react-dom@18.3.1)(react@18.3.1)(scheduler@0.23.2): - resolution: - { - integrity: sha512-Io2ArvcRO+6MWIhkdfMFt+WKQX+Vb++W8DS2l03z/Vw/rz3BclKpM0ynr4LYGyU85Eke+Yx5oIhTY++QR0ZDoA==, - } - peerDependencies: - react: '>=16.8.0' - react-dom: '*' - react-native: '*' - scheduler: '>=0.19.0' - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true + unist-util-stringify-position@4.0.0: dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - scheduler: 0.23.2 - dev: false + '@types/unist': 3.0.3 - /use-isomorphic-layout-effect@1.1.2(@types/react@18.3.1)(react@18.3.1): - resolution: - { - integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==, - } - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true + unist-util-visit-parents@6.0.2: dependencies: - '@types/react': 18.3.1 - react: 18.3.1 - dev: false - - /utf8-byte-length@1.0.4: - resolution: - { - integrity: sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==, - } - dev: false - - /util-deprecate@1.0.2: - resolution: - { - integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, - } - - /uuid@9.0.0: - resolution: - { - integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==, - } - hasBin: true - dev: false + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 - /uuid@9.0.1: - resolution: - { - integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==, - } - hasBin: true - dev: false - - /webidl-conversions@7.0.0: - resolution: - { - integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==, - } - engines: { node: '>=12' } - dev: false - - /whatwg-url@11.0.0: - resolution: - { - integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==, - } - engines: { node: '>=12' } - dependencies: - tr46: 3.0.0 + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + update-browserslist-db@1.2.2(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + use-context-selector@2.0.0(react@19.2.2)(scheduler@0.0.0-experimental-3edc000d-20240926): + dependencies: + react: 19.2.2 + scheduler: 0.0.0-experimental-3edc000d-20240926 + + use-isomorphic-layout-effect@1.2.1(@types/react@19.2.1)(react@19.2.2): + dependencies: + react: 19.2.2 + optionalDependencies: + '@types/react': 19.2.1 + + utf8-byte-length@1.0.5: {} + + util-deprecate@1.0.2: {} + + uuid@10.0.0: {} + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + webidl-conversions@7.0.0: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 webidl-conversions: 7.0.0 - dev: false - - /which-boxed-primitive@1.0.2: - resolution: - { - integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==, - } - dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 - dev: false - - /which-collection@1.0.2: - resolution: - { - integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==, - } - engines: { node: '>= 0.4' } - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.3 - dev: false - - /which-typed-array@1.1.15: - resolution: - { - integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==, - } - engines: { node: '>= 0.4' } - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-tostringtag: 1.0.2 - dev: false - - /which@2.0.2: - resolution: - { - integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, - } - engines: { node: '>= 8' } - hasBin: true + + which@2.0.2: dependencies: isexe: 2.0.0 - /wrap-ansi@7.0.0: - resolution: - { - integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, - } - engines: { node: '>=10' } - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - /wrap-ansi@8.1.0: - resolution: - { - integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==, - } - engines: { node: '>=12' } - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - - /wrappy@1.0.2: - resolution: - { - integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==, - } - dev: false - - /ws@8.17.0: - resolution: - { - integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==, - } - engines: { node: '>=10.0.0' } - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false - - /xss@1.0.15: - resolution: - { - integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==, - } - engines: { node: '>= 0.10.0' } - hasBin: true + wrappy@1.0.2: {} + + ws@8.18.3: {} + + xss@1.0.15: dependencies: commander: 2.20.3 cssfilter: 0.0.10 - dev: false - - /yallist@4.0.0: - resolution: - { - integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==, - } - dev: false - - /yaml@1.10.2: - resolution: - { - integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==, - } - engines: { node: '>= 6' } - dev: false - - /yaml@2.4.2: - resolution: - { - integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==, - } - engines: { node: '>= 14' } - hasBin: true - /yjs@13.6.15: - resolution: - { - integrity: sha512-moFv4uNYhp8BFxIk3AkpoAnnjts7gwdpiG8RtyFiKbMtxKCS0zVZ5wPaaGpwC3V2N/K8TK8MwtSI3+WO9CHWjQ==, - } - engines: { node: '>=16.0.0', npm: '>=8.0.0' } + yaml@1.10.2: {} + + yjs@13.6.27: dependencies: - lib0: 0.2.93 - dev: false + lib0: 0.2.114 + + zwitch@2.0.4: {} diff --git a/examples/whitelabel/package.json b/examples/whitelabel/package.json index ff25b5cb750..93597e02453 100644 --- a/examples/whitelabel/package.json +++ b/examples/whitelabel/package.json @@ -20,7 +20,7 @@ "@payloadcms/richtext-lexical": "latest", "cross-env": "^7.0.3", "graphql": "^16.9.0", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1", diff --git a/examples/whitelabel/pnpm-lock.yaml b/examples/whitelabel/pnpm-lock.yaml index 5bc0de7b468..b310a5d66c3 100644 --- a/examples/whitelabel/pnpm-lock.yaml +++ b/examples/whitelabel/pnpm-lock.yaml @@ -4,23 +4,19 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -overrides: - '@types/react': npm:types-react@19.0.0-rc.1 - '@types/react-dom': npm:types-react-dom@19.0.0-rc.1 - importers: .: dependencies: '@payloadcms/db-mongodb': specifier: latest - version: 3.0.0(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2)) + version: 3.0.0(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)) '@payloadcms/next': specifier: latest - version: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + version: 3.0.0(@types/react@19.2.1)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@payloadcms/richtext-lexical': specifier: latest - version: 3.0.0(g6u7fznlwk7o3blelsxqzzcrzy) + version: 3.0.0(7c424cf623fdc66a437669720f0de38d) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -28,33 +24,33 @@ importers: specifier: ^16.9.0 version: 16.9.0 next: - specifier: ^15.0.0 - version: 15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4) + specifier: ^15.4.9 + version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest - version: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + version: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) react: - specifier: 19.0.0-rc-65a56d0e-20241020 - version: 19.0.0-rc-65a56d0e-20241020 + specifier: ^19.2.1 + version: 19.2.2 react-dom: - specifier: 19.0.0-rc-65a56d0e-20241020 - version: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + specifier: ^19.2.1 + version: 19.2.2(react@19.2.2) sharp: specifier: 0.32.6 version: 0.32.6 devDependencies: '@payloadcms/graphql': specifier: latest - version: 3.0.0(graphql@16.9.0)(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(typescript@5.5.2) + version: 3.0.0(graphql@16.9.0)(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(typescript@5.5.2) '@types/node': specifier: ^20.11.25 version: 20.17.6 '@types/react': - specifier: npm:types-react@19.0.0-rc.1 - version: types-react@19.0.0-rc.1 + specifier: 19.2.1 + version: 19.2.1 '@types/react-dom': - specifier: npm:types-react-dom@19.0.0-rc.1 - version: types-react-dom@19.0.0-rc.1 + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) dotenv: specifier: ^16.4.5 version: 16.4.5 @@ -126,8 +122,8 @@ packages: '@dnd-kit/core@6.0.8': resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} peerDependencies: - react: ^18.2.0 - react-dom: ^18.2.0 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@dnd-kit/sortable@7.0.2': resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} @@ -140,8 +136,8 @@ packages: peerDependencies: react: '>=16.8.0' - '@emnapi/runtime@1.3.1': - resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emotion/babel-plugin@11.12.0': resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==} @@ -401,107 +397,139 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [win32] @@ -619,53 +647,56 @@ packages: '@next/env@15.0.3': resolution: {integrity: sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==} + '@next/env@15.5.8': + resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} + '@next/eslint-plugin-next@15.0.3': resolution: {integrity: sha512-3Ln/nHq2V+v8uIaxCR6YfYo7ceRgZNXfTd3yW1ukTaFbO+/I8jNakrjYWODvG9BuR2v5kgVtH/C8r0i11quOgw==} - '@next/swc-darwin-arm64@15.0.3': - resolution: {integrity: sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==} + '@next/swc-darwin-arm64@15.5.7': + resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.0.3': - resolution: {integrity: sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==} + '@next/swc-darwin-x64@15.5.7': + resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.0.3': - resolution: {integrity: sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==} + '@next/swc-linux-arm64-gnu@15.5.7': + resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-arm64-musl@15.0.3': - resolution: {integrity: sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==} + '@next/swc-linux-arm64-musl@15.5.7': + resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@next/swc-linux-x64-gnu@15.0.3': - resolution: {integrity: sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==} + '@next/swc-linux-x64-gnu@15.5.7': + resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-linux-x64-musl@15.0.3': - resolution: {integrity: sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==} + '@next/swc-linux-x64-musl@15.5.7': + resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@next/swc-win32-arm64-msvc@15.0.3': - resolution: {integrity: sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==} + '@next/swc-win32-arm64-msvc@15.5.7': + resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.0.3': - resolution: {integrity: sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==} + '@next/swc-win32-x64-msvc@15.5.7': + resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -746,11 +777,8 @@ packages: '@rushstack/eslint-patch@1.10.4': resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} - '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - - '@swc/helpers@0.5.13': - resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==} + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} @@ -794,9 +822,17 @@ packages: '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 + '@types/react-transition-group@4.4.11': resolution: {integrity: sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1217,6 +1253,10 @@ packages: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -2080,16 +2120,16 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.0.3: - resolution: {integrity: sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==} + next@15.5.8: + resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 + '@playwright/test': ^1.51.1 babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-66855b96-20241106 - react-dom: ^18.2.0 || 19.0.0-rc-66855b96-20241106 + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': @@ -2322,10 +2362,10 @@ packages: react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 react-dom: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 - react-dom@19.0.0-rc-65a56d0e-20241020: - resolution: {integrity: sha512-OrsgAX3LQ6JtdBJayK4nG1Hj5JebzWyhKSsrP/bmkeFxulb0nG2LaPloJ6kBkAxtgjiwRyGUciJ4+Qu64gy/KA==} + react-dom@19.2.2: + resolution: {integrity: sha512-fhyD2BLrew6qYf4NNtHff1rLXvzR25rq49p+FeqByOazc6TcSi2n8EYulo5C1PbH+1uBW++5S1SG7FcUU6mlDg==} peerDependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: ^19.2.2 react-error-boundary@3.1.4: resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} @@ -2364,8 +2404,8 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' - react@19.0.0-rc-65a56d0e-20241020: - resolution: {integrity: sha512-rZqpfd9PP/A97j9L1MR6fvWSMgs3khgIyLd0E+gYoCcLrxXndj+ySPRVlDPDC3+f7rm8efHNL4B6HeapqU6gzw==} + react@19.2.2: + resolution: {integrity: sha512-BdOGOY8OKRBcgoDkwqA8Q5XvOIhoNx/Sh6BnGJlet2Abt0X5BK0BDrqGyQgLhAVjD2nAg5f6o01u/OPUhG022Q==} engines: {node: '>=0.10.0'} readable-stream@3.6.2: @@ -2448,8 +2488,8 @@ packages: scheduler@0.0.0-experimental-3edc000d-20240926: resolution: {integrity: sha512-360BMNajOhMyrirau0pzWVgeakvrfjbfdqHnX2K+tSGTmn6tBN+6K5NhhaebqeXXWyCU3rl5FApjgF2GN0W5JA==} - scheduler@0.25.0-rc-65a56d0e-20241020: - resolution: {integrity: sha512-HxWcXSy0sNnf+TKRkMwyVD1z19AAVQ4gUub8m7VxJUUfSu3J4lr1T+AagohKEypiW5dbQhJuCtAumPY6z9RQ1g==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} scmp@2.1.0: resolution: {integrity: sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==} @@ -2466,6 +2506,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2478,8 +2523,8 @@ packages: resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} engines: {node: '>=14.15.0'} - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -2718,12 +2763,6 @@ packages: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} - types-react-dom@19.0.0-rc.1: - resolution: {integrity: sha512-VSLZJl8VXCD0fAWp7DUTFUDCcZ8DVXOQmjhJMD03odgeFmu14ZQJHCXeETm3BEAhJqfgJaFkLnGkQv88sRx0fQ==} - - types-react@19.0.0-rc.1: - resolution: {integrity: sha512-RshndUfqTW6K3STLPis8BtAYCGOkMbtvYsi90gmVNDZBXUyUc5juf2PE9LfS/JmOlUIRO8cWTS/1MTnmhjDqyQ==} - typescript@5.5.2: resolution: {integrity: sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==} engines: {node: '>=14.17'} @@ -2916,32 +2955,32 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@dnd-kit/accessibility@3.1.0(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/accessibility@3.1.0(react@19.2.2)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/core@6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/accessibility': 3.1.0(react@19.0.0-rc-65a56d0e-20241020) - '@dnd-kit/utilities': 3.2.2(react@19.0.0-rc-65a56d0e-20241020) - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + '@dnd-kit/accessibility': 3.1.0(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tslib: 2.8.1 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@dnd-kit/utilities': 3.2.2(react@19.0.0-rc-65a56d0e-20241020) - react: 19.0.0-rc-65a56d0e-20241020 + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/utilities': 3.2.2(react@19.2.2) + react: 19.2.2 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.0.0-rc-65a56d0e-20241020)': + '@dnd-kit/utilities@3.2.2(react@19.2.2)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 tslib: 2.8.1 - '@emnapi/runtime@1.3.1': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -2984,19 +3023,19 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.13.3(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)': + '@emotion/react@11.13.3(@types/react@19.2.1)(react@19.2.2)': dependencies: '@babel/runtime': 7.26.0 '@emotion/babel-plugin': 11.12.0 '@emotion/cache': 11.13.1 '@emotion/serialize': 1.3.2 - '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@19.0.0-rc-65a56d0e-20241020) + '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@19.2.2) '@emotion/utils': 1.4.1 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 optionalDependencies: - '@types/react': types-react@19.0.0-rc.1 + '@types/react': 19.2.1 transitivePeerDependencies: - supports-color @@ -3012,9 +3051,9 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@19.0.0-rc-65a56d0e-20241020)': + '@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@19.2.2)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 '@emotion/utils@1.4.1': {} @@ -3115,23 +3154,23 @@ snapshots: '@eslint/js@8.57.1': {} - '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/modal@3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: body-scroll-lock: 4.0.0-beta.0 focus-trap: 7.5.4 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-transition-group: 4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) - '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/scroll-info@2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@faceless-ui/window-info@3.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@floating-ui/core@1.6.8': dependencies: @@ -3142,18 +3181,18 @@ snapshots: '@floating-ui/core': 1.6.8 '@floating-ui/utils': 0.2.8 - '@floating-ui/react-dom@2.1.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@floating-ui/react-dom@2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@floating-ui/dom': 1.6.12 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - '@floating-ui/react@0.26.28(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@floating-ui/react@0.26.28(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: - '@floating-ui/react-dom': 2.1.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@floating-ui/react-dom': 2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@floating-ui/utils': 0.2.8 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) tabbable: 6.2.0 '@floating-ui/utils@0.2.8': {} @@ -3170,79 +3209,101 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@img/sharp-darwin-arm64@0.33.5': + '@img/colour@1.0.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.2.4 optional: true - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': optional: true - '@img/sharp-libvips-darwin-arm64@1.0.4': + '@img/sharp-libvips-linux-ppc64@1.2.4': optional: true - '@img/sharp-libvips-darwin-x64@1.0.4': + '@img/sharp-libvips-linux-riscv64@1.2.4': optional: true - '@img/sharp-libvips-linux-arm64@1.0.4': + '@img/sharp-libvips-linux-s390x@1.2.4': optional: true - '@img/sharp-libvips-linux-arm@1.0.5': + '@img/sharp-libvips-linux-x64@1.2.4': optional: true - '@img/sharp-libvips-linux-s390x@1.0.4': + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': optional: true - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-linuxmusl-x64@1.2.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 optional: true - '@img/sharp-linux-arm64@0.33.5': + '@img/sharp-linux-ppc64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 optional: true - '@img/sharp-linux-arm@0.33.5': + '@img/sharp-linux-riscv64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-riscv64': 1.2.4 optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-s390x@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.2.4 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linuxmusl-arm64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linuxmusl-x64@0.34.5': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 optional: true - '@img/sharp-wasm32@0.33.5': + '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.3.1 + '@emnapi/runtime': 1.7.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-ia32@0.34.5': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-x64@0.34.5': optional: true '@jridgewell/gen-mapping@0.3.5': @@ -3278,7 +3339,7 @@ snapshots: lexical: 0.20.0 prismjs: 1.29.0 - '@lexical/devtools-core@0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@lexical/devtools-core@0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@lexical/html': 0.20.0 '@lexical/link': 0.20.0 @@ -3286,8 +3347,8 @@ snapshots: '@lexical/table': 0.20.0 '@lexical/utils': 0.20.0 lexical: 0.20.0 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@lexical/dragon@0.20.0': dependencies: @@ -3353,11 +3414,11 @@ snapshots: '@lexical/utils': 0.20.0 lexical: 0.20.0 - '@lexical/react@0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(yjs@13.6.20)': + '@lexical/react@0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.20)': dependencies: '@lexical/clipboard': 0.20.0 '@lexical/code': 0.20.0 - '@lexical/devtools-core': 0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@lexical/devtools-core': 0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@lexical/dragon': 0.20.0 '@lexical/hashtag': 0.20.0 '@lexical/history': 0.20.0 @@ -3374,9 +3435,9 @@ snapshots: '@lexical/utils': 0.20.0 '@lexical/yjs': 0.20.0(yjs@13.6.20) lexical: 0.20.0 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-error-boundary: 3.1.4(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 3.1.4(react@19.2.2) transitivePeerDependencies: - yjs @@ -3420,12 +3481,12 @@ snapshots: monaco-editor: 0.52.0 state-local: 1.0.7 - '@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)': + '@monaco-editor/react@4.6.0(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)': dependencies: '@monaco-editor/loader': 1.4.0(monaco-editor@0.52.0) monaco-editor: 0.52.0 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) '@mongodb-js/saslprep@1.1.9': dependencies: @@ -3433,32 +3494,34 @@ snapshots: '@next/env@15.0.3': {} + '@next/env@15.5.8': {} + '@next/eslint-plugin-next@15.0.3': dependencies: fast-glob: 3.3.1 - '@next/swc-darwin-arm64@15.0.3': + '@next/swc-darwin-arm64@15.5.7': optional: true - '@next/swc-darwin-x64@15.0.3': + '@next/swc-darwin-x64@15.5.7': optional: true - '@next/swc-linux-arm64-gnu@15.0.3': + '@next/swc-linux-arm64-gnu@15.5.7': optional: true - '@next/swc-linux-arm64-musl@15.0.3': + '@next/swc-linux-arm64-musl@15.5.7': optional: true - '@next/swc-linux-x64-gnu@15.0.3': + '@next/swc-linux-x64-gnu@15.5.7': optional: true - '@next/swc-linux-x64-musl@15.0.3': + '@next/swc-linux-x64-musl@15.5.7': optional: true - '@next/swc-win32-arm64-msvc@15.0.3': + '@next/swc-win32-arm64-msvc@15.5.7': optional: true - '@next/swc-win32-x64-msvc@15.0.3': + '@next/swc-win32-x64-msvc@15.5.7': optional: true '@nodelib/fs.scandir@2.1.5': @@ -3475,13 +3538,13 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@payloadcms/db-mongodb@3.0.0(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))': + '@payloadcms/db-mongodb@3.0.0(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))': dependencies: http-status: 1.6.2 mongoose: 8.8.1 mongoose-aggregate-paginate-v2: 1.1.2 mongoose-paginate-v2: 1.8.5 - payload: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) prompts: 2.4.2 uuid: 10.0.0 transitivePeerDependencies: @@ -3494,36 +3557,36 @@ snapshots: - socks - supports-color - '@payloadcms/graphql@3.0.0(graphql@16.9.0)(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(typescript@5.5.2)': + '@payloadcms/graphql@3.0.0(graphql@16.9.0)(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(typescript@5.5.2)': dependencies: graphql: 16.9.0 graphql-scalars: 1.22.2(graphql@16.9.0) - payload: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) pluralize: 8.0.0 ts-essentials: 10.0.3(typescript@5.5.2) tsx: 4.19.2 transitivePeerDependencies: - typescript - '@payloadcms/next@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2)': + '@payloadcms/next@3.0.0(@types/react@19.2.1)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@payloadcms/graphql': 3.0.0(graphql@16.9.0)(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(typescript@5.5.2) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@payloadcms/graphql': 3.0.0(graphql@16.9.0)(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(typescript@5.5.2) '@payloadcms/translations': 3.0.0 - '@payloadcms/ui': 3.0.0(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + '@payloadcms/ui': 3.0.0(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) busboy: 1.6.0 file-type: 19.3.0 graphql: 16.9.0 graphql-http: 1.22.2(graphql@16.9.0) graphql-playground-html: 1.6.30 http-status: 1.6.2 - next: 15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) path-to-regexp: 6.3.0 - payload: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) qs-esm: 7.0.2 - react-diff-viewer-continued: 3.2.6(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + react-diff-viewer-continued: 3.2.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2) sass: 1.77.4 - sonner: 1.7.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + sonner: 1.7.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -3533,23 +3596,23 @@ snapshots: - supports-color - typescript - '@payloadcms/richtext-lexical@3.0.0(g6u7fznlwk7o3blelsxqzzcrzy)': + '@payloadcms/richtext-lexical@3.0.0(7c424cf623fdc66a437669720f0de38d)': dependencies: - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@lexical/headless': 0.20.0 '@lexical/link': 0.20.0 '@lexical/list': 0.20.0 '@lexical/mark': 0.20.0 '@lexical/markdown': 0.20.0 - '@lexical/react': 0.20.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(yjs@13.6.20) + '@lexical/react': 0.20.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(yjs@13.6.20) '@lexical/rich-text': 0.20.0 '@lexical/selection': 0.20.0 '@lexical/table': 0.20.0 '@lexical/utils': 0.20.0 - '@payloadcms/next': 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + '@payloadcms/next': 3.0.0(@types/react@19.2.1)(graphql@16.9.0)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@payloadcms/translations': 3.0.0 - '@payloadcms/ui': 3.0.0(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2) + '@payloadcms/ui': 3.0.0(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -3559,10 +3622,10 @@ snapshots: mdast-util-from-markdown: 2.0.2 mdast-util-mdx-jsx: 3.1.3 micromark-extension-mdx-jsx: 3.0.1 - payload: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-error-boundary: 4.0.13(react@19.0.0-rc-65a56d0e-20241020) + payload: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-error-boundary: 4.0.13(react@19.2.2) ts-essentials: 10.0.3(typescript@5.5.2) uuid: 10.0.0 transitivePeerDependencies: @@ -3576,34 +3639,34 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.0.0(monaco-editor@0.52.0)(next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2))(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1)(typescript@5.5.2)': + '@payloadcms/ui@3.0.0(@types/react@19.2.1)(monaco-editor@0.52.0)(next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(react@19.2.2) + '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@faceless-ui/window-info': 3.0.0-beta.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/translations': 3.0.0 body-scroll-lock: 4.0.0-beta.0 bson-objectid: 2.0.4 date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4) + next: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) object-to-formdata: 4.5.1 - payload: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2) + payload: 3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2) qs-esm: 7.0.2 - react: 19.0.0-rc-65a56d0e-20241020 - react-animate-height: 2.1.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - react-datepicker: 6.9.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-image-crop: 10.1.8(react@19.0.0-rc-65a56d0e-20241020) - react-select: 5.8.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + react: 19.2.2 + react-animate-height: 2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-datepicker: 6.9.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + react-dom: 19.2.2(react@19.2.2) + react-image-crop: 10.1.8(react@19.2.2) + react-select: 5.8.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) scheduler: 0.0.0-experimental-3edc000d-20240926 - sonner: 1.7.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + sonner: 1.7.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) ts-essentials: 10.0.3(typescript@5.5.2) - use-context-selector: 2.0.0(react@19.0.0-rc-65a56d0e-20241020)(scheduler@0.0.0-experimental-3edc000d-20240926) + use-context-selector: 2.0.0(react@19.2.2)(scheduler@0.0.0-experimental-3edc000d-20240926) uuid: 10.0.0 transitivePeerDependencies: - '@types/react' @@ -3615,9 +3678,7 @@ snapshots: '@rushstack/eslint-patch@1.10.4': {} - '@swc/counter@0.1.3': {} - - '@swc/helpers@0.5.13': + '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 @@ -3663,9 +3724,17 @@ snapshots: '@types/parse-json@4.0.2': {} + '@types/react-dom@19.2.1(@types/react@19.2.1)': + dependencies: + '@types/react': 19.2.1 + '@types/react-transition-group@4.4.11': dependencies: - '@types/react': types-react@19.0.0-rc.1 + '@types/react': 19.2.1 + + '@types/react@19.2.1': + dependencies: + csstype: 3.1.3 '@types/unist@2.0.11': {} @@ -4119,6 +4188,9 @@ snapshots: detect-libc@2.0.3: {} + detect-libc@2.1.2: + optional: true + devlop@1.1.0: dependencies: dequal: 2.0.3 @@ -4313,7 +4385,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -4326,7 +4398,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -4348,7 +4420,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.15.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -5241,28 +5313,26 @@ snapshots: natural-compare@1.4.0: {} - next@15.0.3(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(sass@1.77.4): + next@15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): dependencies: - '@next/env': 15.0.3 - '@swc/counter': 0.1.3 - '@swc/helpers': 0.5.13 - busboy: 1.6.0 + '@next/env': 15.5.8 + '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001680 postcss: 8.4.31 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - styled-jsx: 5.1.6(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + styled-jsx: 5.1.6(react@19.2.2) optionalDependencies: - '@next/swc-darwin-arm64': 15.0.3 - '@next/swc-darwin-x64': 15.0.3 - '@next/swc-linux-arm64-gnu': 15.0.3 - '@next/swc-linux-arm64-musl': 15.0.3 - '@next/swc-linux-x64-gnu': 15.0.3 - '@next/swc-linux-x64-musl': 15.0.3 - '@next/swc-win32-arm64-msvc': 15.0.3 - '@next/swc-win32-x64-msvc': 15.0.3 + '@next/swc-darwin-arm64': 15.5.7 + '@next/swc-darwin-x64': 15.5.7 + '@next/swc-linux-arm64-gnu': 15.5.7 + '@next/swc-linux-arm64-musl': 15.5.7 + '@next/swc-linux-x64-gnu': 15.5.7 + '@next/swc-linux-x64-musl': 15.5.7 + '@next/swc-win32-arm64-msvc': 15.5.7 + '@next/swc-win32-x64-msvc': 15.5.7 sass: 1.77.4 - sharp: 0.33.5 + sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -5372,9 +5442,9 @@ snapshots: path-type@4.0.0: {} - payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(typescript@5.5.2): + payload@3.0.0(graphql@16.9.0)(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.5.2): dependencies: - '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@monaco-editor/react': 4.6.0(monaco-editor@0.52.0)(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@next/env': 15.0.3 '@payloadcms/translations': 3.0.0 '@types/busboy': 1.5.4 @@ -5524,88 +5594,88 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-animate-height@2.1.2(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-animate-height@2.1.2(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: classnames: 2.5.1 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react-datepicker@6.9.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-datepicker@6.9.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - '@floating-ui/react': 0.26.28(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + '@floating-ui/react': 0.26.28(react-dom@19.2.2(react@19.2.2))(react@19.2.2) clsx: 2.1.1 date-fns: 3.6.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-onclickoutside: 6.13.1(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-onclickoutside: 6.13.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2) - react-diff-viewer-continued@3.2.6(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-diff-viewer-continued@3.2.6(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@emotion/css': 11.13.4 classnames: 2.5.1 diff: 5.2.0 memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) transitivePeerDependencies: - supports-color - react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020): + react-dom@19.2.2(react@19.2.2): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - scheduler: 0.25.0-rc-65a56d0e-20241020 + react: 19.2.2 + scheduler: 0.27.0 - react-error-boundary@3.1.4(react@19.0.0-rc-65a56d0e-20241020): + react-error-boundary@3.1.4(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 - react-error-boundary@4.0.13(react@19.0.0-rc-65a56d0e-20241020): + react-error-boundary@4.0.13(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 - react-image-crop@10.1.8(react@19.0.0-rc-65a56d0e-20241020): + react-image-crop@10.1.8(react@19.2.2): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 react-is@16.13.1: {} - react-onclickoutside@6.13.1(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-onclickoutside@6.13.1(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react-select@5.8.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1): + react-select@5.8.0(@types/react@19.2.1)(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 '@emotion/cache': 11.13.1 - '@emotion/react': 11.13.3(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + '@emotion/react': 11.13.3(@types/react@19.2.1)(react@19.2.2) '@floating-ui/dom': 1.6.12 '@types/react-transition-group': 4.4.11 memoize-one: 6.0.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) - react-transition-group: 4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020) - use-isomorphic-layout-effect: 1.1.2(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) + react-transition-group: 4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2) + use-isomorphic-layout-effect: 1.1.2(@types/react@19.2.1)(react@19.2.2) transitivePeerDependencies: - '@types/react' - supports-color - react-transition-group@4.4.5(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + react-transition-group@4.4.5(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: '@babel/runtime': 7.26.0 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) - react@19.0.0-rc-65a56d0e-20241020: {} + react@19.2.2: {} readable-stream@3.6.2: dependencies: @@ -5695,7 +5765,7 @@ snapshots: scheduler@0.0.0-experimental-3edc000d-20240926: {} - scheduler@0.25.0-rc-65a56d0e-20241020: {} + scheduler@0.27.0: {} scmp@2.1.0: {} @@ -5705,6 +5775,9 @@ snapshots: semver@7.6.3: {} + semver@7.7.3: + optional: true + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5732,31 +5805,36 @@ snapshots: tar-fs: 3.0.6 tunnel-agent: 0.6.0 - sharp@0.33.5: + sharp@0.34.5: dependencies: - color: 4.2.3 - detect-libc: 2.0.3 - semver: 7.6.3 + '@img/colour': 1.0.0 + detect-libc: 2.1.2 + semver: 7.7.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 optional: true shebang-command@2.0.0: @@ -5794,10 +5872,10 @@ snapshots: dependencies: atomic-sleep: 1.0.0 - sonner@1.7.0(react-dom@19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020))(react@19.0.0-rc-65a56d0e-20241020): + sonner@1.7.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 - react-dom: 19.0.0-rc-65a56d0e-20241020(react@19.0.0-rc-65a56d0e-20241020) + react: 19.2.2 + react-dom: 19.2.2(react@19.2.2) source-map-js@1.2.1: {} @@ -5890,10 +5968,10 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 5.3.1 - styled-jsx@5.1.6(react@19.0.0-rc-65a56d0e-20241020): + styled-jsx@5.1.6(react@19.2.2): dependencies: client-only: 0.0.1 - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 stylis@4.2.0: {} @@ -6032,14 +6110,6 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - types-react-dom@19.0.0-rc.1: - dependencies: - '@types/react': types-react@19.0.0-rc.1 - - types-react@19.0.0-rc.1: - dependencies: - csstype: 3.1.3 - typescript@5.5.2: {} uint8array-extras@1.4.0: {} @@ -6080,16 +6150,16 @@ snapshots: dependencies: punycode: 2.3.1 - use-context-selector@2.0.0(react@19.0.0-rc-65a56d0e-20241020)(scheduler@0.0.0-experimental-3edc000d-20240926): + use-context-selector@2.0.0(react@19.2.2)(scheduler@0.0.0-experimental-3edc000d-20240926): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 scheduler: 0.0.0-experimental-3edc000d-20240926 - use-isomorphic-layout-effect@1.1.2(react@19.0.0-rc-65a56d0e-20241020)(types-react@19.0.0-rc.1): + use-isomorphic-layout-effect@1.1.2(@types/react@19.2.1)(react@19.2.2): dependencies: - react: 19.0.0-rc-65a56d0e-20241020 + react: 19.2.2 optionalDependencies: - '@types/react': types-react@19.0.0-rc.1 + '@types/react': 19.2.1 utf8-byte-length@1.0.5: {} diff --git a/package.json b/package.json index 3d2c7815fd7..1d7fc2e63ce 100644 --- a/package.json +++ b/package.json @@ -180,7 +180,7 @@ "minimist": "1.2.8", "mongodb-memory-server": "10.1.4", "mongoose": "8.15.1", - "next": "15.4.8", + "next": "15.4.9", "open": "^10.1.0", "p-limit": "^5.0.0", "pg": "8.16.3", diff --git a/packages/next/package.json b/packages/next/package.json index bbc565a5763..f0612278dc5 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -143,7 +143,7 @@ }, "peerDependencies": { "graphql": "^16.8.1", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "workspace:*" }, "engines": { diff --git a/packages/ui/package.json b/packages/ui/package.json index e5e5dd9556a..b659acb3164 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -178,7 +178,7 @@ "payload": "workspace:*" }, "peerDependencies": { - "next": "^15.2.6 || ^15.3.6 || ^15.4.8 || ^15.5.7", + "next": "^15.2.7 || ^15.3.7 || ^15.4.9 || ^15.5.8", "payload": "workspace:*", "react": "^19.0.1 || ^19.1.2 || ^19.2.1", "react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1525d59750..0325fe7419f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,7 +47,7 @@ importers: version: 1.56.1 '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) '@sentry/node': specifier: ^8.33.1 version: 8.37.1 @@ -145,8 +145,8 @@ importers: specifier: 8.15.1 version: 8.15.1(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: - specifier: 15.4.8 - version: 15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.9 + version: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) open: specifier: ^10.1.0 version: 10.1.0 @@ -803,8 +803,8 @@ importers: specifier: 2.1.0 version: 2.1.0 next: - specifier: ^15.4.8 - version: 15.4.8(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: ^15.4.9 + version: 15.4.9(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) path-to-regexp: specifier: 6.3.0 version: 6.3.0 @@ -1762,8 +1762,8 @@ importers: specifier: 2.3.0 version: 2.3.0 next: - specifier: ^15.2.6 || ^15.3.6 || ^15.4.8 || ^15.5.7 - version: 15.4.8(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: ^15.2.7 || ^15.3.7 || ^15.4.9 || ^15.5.8 + version: 15.4.9(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) object-to-formdata: specifier: 4.5.1 version: 4.5.1 @@ -1868,8 +1868,8 @@ importers: specifier: ^16.8.1 version: 16.9.0 next: - specifier: 15.4.8 - version: 15.4.8(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.9 + version: 15.4.9(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: workspace:* version: link:../../packages/payload @@ -2011,7 +2011,7 @@ importers: version: 8.6.0(react@19.2.1) geist: specifier: ^1.3.0 - version: 1.4.2(next@15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.4.2(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) graphql: specifier: ^16.8.1 version: 16.9.0 @@ -2022,8 +2022,8 @@ importers: specifier: ^0.477.0 version: 0.477.0(react@19.2.1) next: - specifier: 15.4.8 - version: 15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.9 + version: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes: specifier: 0.4.6 version: 0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -2210,7 +2210,7 @@ importers: version: 16.4.7 geist: specifier: ^1.3.0 - version: 1.4.2(next@15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.4.2(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) graphql: specifier: ^16.8.1 version: 16.9.0 @@ -2218,11 +2218,11 @@ importers: specifier: ^0.378.0 version: 0.378.0(react@19.2.1) next: - specifier: 15.4.8 - version: 15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.9 + version: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-sitemap: specifier: ^4.2.3 - version: 4.2.3(next@15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 4.2.3(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) payload: specifier: workspace:* version: link:../../packages/payload @@ -2463,7 +2463,7 @@ importers: version: link:../packages/ui '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) '@sentry/react': specifier: ^7.77.0 version: 7.119.2(react@19.2.1) @@ -2534,8 +2534,8 @@ importers: specifier: 8.15.1 version: 8.15.1(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: - specifier: 15.4.8 - version: 15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.9 + version: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) nodemailer: specifier: 7.0.9 version: 7.0.9 @@ -5735,8 +5735,8 @@ packages: '@next/env@15.4.7': resolution: {integrity: sha512-PrBIpO8oljZGTOe9HH0miix1w5MUiGJ/q83Jge03mHEE0E3pyqzAy2+l5G6aJDbXoobmxPJTVhbCuwlLtjSHwg==} - '@next/env@15.4.8': - resolution: {integrity: sha512-LydLa2MDI1NMrOFSkO54mTc8iIHSttj6R6dthITky9ylXV2gCGi0bHQjVCtLGRshdRPjyh2kXbxJukDtBWQZtQ==} + '@next/env@15.4.9': + resolution: {integrity: sha512-OYR0RulK5phnbxxzcLE4/ECgfx1PL3EHrDbjyelJ7jauaO+/Qvj5gG8JPMltB51CygC2KrZ0aAfYLjPYjYY17A==} '@next/env@15.5.4': resolution: {integrity: sha512-27SQhYp5QryzIT5uO8hq99C69eLQ7qkzkDPsk3N+GuS2XgOgoYEeOav7Pf8Tn4drECOVDsDg8oj+/DVy8qQL2A==} @@ -12182,8 +12182,8 @@ packages: react: 19.2.1 react-dom: 19.2.1 - next@15.4.8: - resolution: {integrity: sha512-jwOXTz/bo0Pvlf20FSb6VXVeWRssA2vbvq9SdrOPEg9x8E1B27C2rQtvriAn600o9hH61kjrVRexEffv3JybuA==} + next@15.4.9: + resolution: {integrity: sha512-/NedNmbiH4Umt/7SohT9VKxEdBt02Lj33xHrukE7d8Li6juT+75sEq4a4U06jggrvdbklKgr78OZEyWZ8XRrtw==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -12206,6 +12206,7 @@ packages: next@15.5.4: resolution: {integrity: sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -18637,7 +18638,7 @@ snapshots: '@img/sharp-wasm32@0.34.3': dependencies: - '@emnapi/runtime': 1.4.5 + '@emnapi/runtime': 1.7.1 optional: true '@img/sharp-win32-arm64@0.34.2': @@ -19281,7 +19282,7 @@ snapshots: '@next/env@15.4.7': {} - '@next/env@15.4.8': {} + '@next/env@15.4.9': {} '@next/env@15.5.4': {} @@ -20449,7 +20450,7 @@ snapshots: '@sentry/utils': 7.119.2 localforage: 1.10.0 - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -20465,7 +20466,7 @@ snapshots: '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.15.3)) chalk: 3.0.0 - next: 15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -25091,9 +25092,9 @@ snapshots: - encoding - supports-color - geist@1.4.2(next@15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + geist@1.4.2(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: - next: 15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) gel@2.0.1: dependencies: @@ -27035,22 +27036,22 @@ snapshots: transitivePeerDependencies: - supports-color - next-sitemap@4.2.3(next@15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + next-sitemap@4.2.3(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: '@corex/deepmerge': 4.0.43 '@next/env': 13.5.11 fast-glob: 3.3.2 minimist: 1.2.8 - next: 15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes@0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: react: 19.2.1 react-dom: 19.2.1(react@19.2.1) - next@15.4.8(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.9(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.4.8 + '@next/env': 15.4.9 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001720 postcss: 8.4.31 @@ -27075,9 +27076,9 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.4.8(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.9(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.4.8 + '@next/env': 15.4.9 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001720 postcss: 8.4.31 @@ -27101,9 +27102,9 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.4.8(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.4.8 + '@next/env': 15.4.9 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001720 postcss: 8.4.31 diff --git a/templates/_template/package.json b/templates/_template/package.json index 83b3bcfd59e..bef60ef5dab 100644 --- a/templates/_template/package.json +++ b/templates/_template/package.json @@ -24,7 +24,7 @@ "@payloadcms/ui": "latest", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "15.4.8", + "next": "15.4.9", "payload": "latest", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/templates/blank/package.json b/templates/blank/package.json index 78ea007c66e..738eed3d09a 100644 --- a/templates/blank/package.json +++ b/templates/blank/package.json @@ -25,7 +25,7 @@ "cross-env": "^7.0.3", "dotenv": "16.4.7", "graphql": "^16.8.1", - "next": "15.4.8", + "next": "15.4.9", "payload": "workspace:*", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/templates/ecommerce/package.json b/templates/ecommerce/package.json index 54496d69f0e..01f9a04765b 100644 --- a/templates/ecommerce/package.json +++ b/templates/ecommerce/package.json @@ -52,7 +52,7 @@ "graphql": "^16.8.2", "jsonwebtoken": "9.0.1", "lucide-react": "^0.477.0", - "next": "15.4.8", + "next": "15.4.9", "next-themes": "0.4.6", "payload": "workspace:*", "prism-react-renderer": "^2.3.1", diff --git a/templates/plugin/package.json b/templates/plugin/package.json index a2693ebb5b2..c4c868b3dee 100644 --- a/templates/plugin/package.json +++ b/templates/plugin/package.json @@ -65,7 +65,7 @@ "eslint-config-next": "15.4.7", "graphql": "^16.8.1", "mongodb-memory-server": "10.1.4", - "next": "15.4.8", + "next": "15.4.9", "open": "^10.1.0", "payload": "3.37.0", "prettier": "^3.4.2", diff --git a/templates/website/package.json b/templates/website/package.json index 3a06893507a..d8952ca4248 100644 --- a/templates/website/package.json +++ b/templates/website/package.json @@ -44,7 +44,7 @@ "geist": "^1.3.0", "graphql": "^16.8.2", "lucide-react": "^0.378.0", - "next": "15.4.8", + "next": "15.4.9", "next-sitemap": "^4.2.3", "payload": "workspace:*", "prism-react-renderer": "^2.3.1", diff --git a/templates/with-cloudflare-d1/package.json b/templates/with-cloudflare-d1/package.json index ca578347e68..22bfe347c3a 100644 --- a/templates/with-cloudflare-d1/package.json +++ b/templates/with-cloudflare-d1/package.json @@ -34,7 +34,7 @@ "cross-env": "^7.0.3", "dotenv": "16.4.7", "graphql": "^16.8.1", - "next": "15.4.8", + "next": "15.4.9", "payload": "3.63.0", "react": "19.2.1", "react-dom": "19.2.1" diff --git a/templates/with-postgres/package.json b/templates/with-postgres/package.json index 5d65c62f908..b2de7db291a 100644 --- a/templates/with-postgres/package.json +++ b/templates/with-postgres/package.json @@ -25,7 +25,7 @@ "@payloadcms/ui": "3.63.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "15.4.8", + "next": "15.4.9", "payload": "3.63.0", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/templates/with-vercel-mongodb/package.json b/templates/with-vercel-mongodb/package.json index 67726b6e871..9014b974171 100644 --- a/templates/with-vercel-mongodb/package.json +++ b/templates/with-vercel-mongodb/package.json @@ -25,7 +25,7 @@ "@payloadcms/ui": "3.63.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "15.4.8", + "next": "15.4.9", "payload": "3.63.0", "react": "19.2.1", "react-dom": "19.2.1" diff --git a/templates/with-vercel-postgres/package.json b/templates/with-vercel-postgres/package.json index ab7a8d00e82..58dc84b63e5 100644 --- a/templates/with-vercel-postgres/package.json +++ b/templates/with-vercel-postgres/package.json @@ -26,7 +26,7 @@ "@payloadcms/ui": "3.63.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "15.4.8", + "next": "15.4.9", "payload": "3.63.0", "react": "19.2.1", "react-dom": "19.2.1" diff --git a/templates/with-vercel-website/package.json b/templates/with-vercel-website/package.json index e3ab8b79c91..26db6716c9b 100644 --- a/templates/with-vercel-website/package.json +++ b/templates/with-vercel-website/package.json @@ -46,7 +46,7 @@ "geist": "^1.3.0", "graphql": "^16.8.2", "lucide-react": "^0.378.0", - "next": "15.4.8", + "next": "15.4.9", "next-sitemap": "^4.2.3", "payload": "3.63.0", "prism-react-renderer": "^2.3.1", diff --git a/test/package.json b/test/package.json index 2042a9e15f8..468c846ce3e 100644 --- a/test/package.json +++ b/test/package.json @@ -94,7 +94,7 @@ "jest": "29.7.0", "jwt-decode": "4.0.0", "mongoose": "8.15.1", - "next": "15.4.8", + "next": "15.4.9", "nodemailer": "7.0.9", "object-to-formdata": "4.5.1", "payload": "workspace:*", diff --git a/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md b/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md index 1feb6280b7b..a678970724b 100644 --- a/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md +++ b/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md @@ -149,7 +149,7 @@ plugin-/ "copyfiles": "^2.4.1", "cross-env": "^7.0.3", "eslint": "^9.0.0", - "next": "^15.4.8", + "next": "^15.4.9", "payload": "^3.0.0", "react": "^19.2.1", "react-dom": "^19.2.1", From 410cfa44612f5f6607991503e5456b2796f505c5 Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Thu, 11 Dec 2025 17:36:04 -0500 Subject: [PATCH 03/67] chore(release): v3.68.3 [skip ci] --- package.json | 2 +- packages/admin-bar/package.json | 2 +- packages/create-payload-app/package.json | 2 +- packages/db-d1-sqlite/package.json | 2 +- packages/db-mongodb/package.json | 2 +- packages/db-postgres/package.json | 2 +- packages/db-sqlite/package.json | 2 +- packages/db-vercel-postgres/package.json | 2 +- packages/drizzle/package.json | 2 +- packages/email-nodemailer/package.json | 2 +- packages/email-resend/package.json | 2 +- packages/graphql/package.json | 2 +- packages/kv-redis/package.json | 2 +- packages/live-preview-react/package.json | 2 +- packages/live-preview-vue/package.json | 2 +- packages/live-preview/package.json | 2 +- packages/next/package.json | 2 +- packages/payload-cloud/package.json | 2 +- packages/payload/package.json | 2 +- packages/plugin-cloud-storage/package.json | 2 +- packages/plugin-ecommerce/package.json | 2 +- packages/plugin-form-builder/package.json | 2 +- packages/plugin-import-export/package.json | 2 +- packages/plugin-mcp/package.json | 2 +- packages/plugin-multi-tenant/package.json | 2 +- packages/plugin-nested-docs/package.json | 2 +- packages/plugin-redirects/package.json | 2 +- packages/plugin-search/package.json | 2 +- packages/plugin-sentry/package.json | 2 +- packages/plugin-seo/package.json | 2 +- packages/plugin-stripe/package.json | 2 +- packages/richtext-lexical/package.json | 2 +- packages/richtext-slate/package.json | 2 +- packages/sdk/package.json | 2 +- packages/storage-azure/package.json | 2 +- packages/storage-gcs/package.json | 2 +- packages/storage-r2/package.json | 2 +- packages/storage-s3/package.json | 2 +- packages/storage-uploadthing/package.json | 2 +- packages/storage-vercel-blob/package.json | 2 +- packages/translations/package.json | 2 +- packages/ui/package.json | 2 +- 42 files changed, 42 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 1d7fc2e63ce..cc0f0fb202a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload-monorepo", - "version": "3.68.2", + "version": "3.68.3", "private": true, "type": "module", "workspaces": [ diff --git a/packages/admin-bar/package.json b/packages/admin-bar/package.json index c64fe7eb711..14d4443aa2f 100644 --- a/packages/admin-bar/package.json +++ b/packages/admin-bar/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/admin-bar", - "version": "3.68.2", + "version": "3.68.3", "description": "An admin bar for React apps using Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/create-payload-app/package.json b/packages/create-payload-app/package.json index f237eda418c..3873c810d89 100644 --- a/packages/create-payload-app/package.json +++ b/packages/create-payload-app/package.json @@ -1,6 +1,6 @@ { "name": "create-payload-app", - "version": "3.68.2", + "version": "3.68.3", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/db-d1-sqlite/package.json b/packages/db-d1-sqlite/package.json index 00f851f74e4..3dabde099ae 100644 --- a/packages/db-d1-sqlite/package.json +++ b/packages/db-d1-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-d1-sqlite", - "version": "3.68.2", + "version": "3.68.3", "description": "The officially supported D1 SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-mongodb/package.json b/packages/db-mongodb/package.json index acdc0a7e225..a3094f2b137 100644 --- a/packages/db-mongodb/package.json +++ b/packages/db-mongodb/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-mongodb", - "version": "3.68.2", + "version": "3.68.3", "description": "The officially supported MongoDB database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-postgres/package.json b/packages/db-postgres/package.json index 075d3e889f0..da62f416374 100644 --- a/packages/db-postgres/package.json +++ b/packages/db-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-postgres", - "version": "3.68.2", + "version": "3.68.3", "description": "The officially supported Postgres database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-sqlite/package.json b/packages/db-sqlite/package.json index 354c67f9eb1..0ca92937acb 100644 --- a/packages/db-sqlite/package.json +++ b/packages/db-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-sqlite", - "version": "3.68.2", + "version": "3.68.3", "description": "The officially supported SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-vercel-postgres/package.json b/packages/db-vercel-postgres/package.json index 2a5e85d4a67..de8c01c555d 100644 --- a/packages/db-vercel-postgres/package.json +++ b/packages/db-vercel-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-vercel-postgres", - "version": "3.68.2", + "version": "3.68.3", "description": "Vercel Postgres adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/drizzle/package.json b/packages/drizzle/package.json index 4ed9148a6fe..4a92d2789d6 100644 --- a/packages/drizzle/package.json +++ b/packages/drizzle/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/drizzle", - "version": "3.68.2", + "version": "3.68.3", "description": "A library of shared functions used by different payload database adapters", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-nodemailer/package.json b/packages/email-nodemailer/package.json index 473a5d7e426..3fc82426739 100644 --- a/packages/email-nodemailer/package.json +++ b/packages/email-nodemailer/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-nodemailer", - "version": "3.68.2", + "version": "3.68.3", "description": "Payload Nodemailer Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-resend/package.json b/packages/email-resend/package.json index 808899caac7..0c89d6a2603 100644 --- a/packages/email-resend/package.json +++ b/packages/email-resend/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-resend", - "version": "3.68.2", + "version": "3.68.3", "description": "Payload Resend Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/graphql/package.json b/packages/graphql/package.json index 3a9997429db..39048d1f1fa 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/graphql", - "version": "3.68.2", + "version": "3.68.3", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/kv-redis/package.json b/packages/kv-redis/package.json index 996df1fd131..fd46bec3ccd 100644 --- a/packages/kv-redis/package.json +++ b/packages/kv-redis/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/kv-redis", - "version": "3.68.2", + "version": "3.68.3", "description": "Redis KV adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-react/package.json b/packages/live-preview-react/package.json index f632ba31489..6e7e5c6c8d1 100644 --- a/packages/live-preview-react/package.json +++ b/packages/live-preview-react/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-react", - "version": "3.68.2", + "version": "3.68.3", "description": "The official React SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-vue/package.json b/packages/live-preview-vue/package.json index c882f08b5f2..b39ab370001 100644 --- a/packages/live-preview-vue/package.json +++ b/packages/live-preview-vue/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-vue", - "version": "3.68.2", + "version": "3.68.3", "description": "The official Vue SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview/package.json b/packages/live-preview/package.json index 2d43c158b91..622ea183c54 100644 --- a/packages/live-preview/package.json +++ b/packages/live-preview/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview", - "version": "3.68.2", + "version": "3.68.3", "description": "The official live preview JavaScript SDK for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/next/package.json b/packages/next/package.json index f0612278dc5..ba90d8b09f3 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/next", - "version": "3.68.2", + "version": "3.68.3", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index 5ebb856b142..1fcf0d97426 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/payload-cloud", - "version": "3.68.2", + "version": "3.68.3", "description": "The official Payload Cloud plugin", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/payload/package.json b/packages/payload/package.json index 8f91b956a70..6b8a58c5e8c 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "3.68.2", + "version": "3.68.3", "description": "Node, React, Headless CMS and Application Framework built on Next.js", "keywords": [ "admin panel", diff --git a/packages/plugin-cloud-storage/package.json b/packages/plugin-cloud-storage/package.json index ce12bf74b96..fd2513ff776 100644 --- a/packages/plugin-cloud-storage/package.json +++ b/packages/plugin-cloud-storage/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-cloud-storage", - "version": "3.68.2", + "version": "3.68.3", "description": "The official cloud storage plugin for Payload CMS", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-ecommerce/package.json b/packages/plugin-ecommerce/package.json index e2d5c1f4619..c1ac02b0dab 100644 --- a/packages/plugin-ecommerce/package.json +++ b/packages/plugin-ecommerce/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-ecommerce", - "version": "3.68.2", + "version": "3.68.3", "description": "Ecommerce plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-form-builder/package.json b/packages/plugin-form-builder/package.json index 789f16cc7b9..7719bde98e3 100644 --- a/packages/plugin-form-builder/package.json +++ b/packages/plugin-form-builder/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-form-builder", - "version": "3.68.2", + "version": "3.68.3", "description": "Form builder plugin for Payload CMS", "keywords": [ "payload", diff --git a/packages/plugin-import-export/package.json b/packages/plugin-import-export/package.json index 3964f8591e7..ed2be7e62fb 100644 --- a/packages/plugin-import-export/package.json +++ b/packages/plugin-import-export/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-import-export", - "version": "3.68.2", + "version": "3.68.3", "description": "Import-Export plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-mcp/package.json b/packages/plugin-mcp/package.json index dc96d9726fa..dae9e34ec50 100644 --- a/packages/plugin-mcp/package.json +++ b/packages/plugin-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-mcp", - "version": "3.68.2", + "version": "3.68.3", "description": "MCP (Model Context Protocol) capabilities with Payload", "keywords": [ "plugin", diff --git a/packages/plugin-multi-tenant/package.json b/packages/plugin-multi-tenant/package.json index 0cd279fbff9..46744390077 100644 --- a/packages/plugin-multi-tenant/package.json +++ b/packages/plugin-multi-tenant/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-multi-tenant", - "version": "3.68.2", + "version": "3.68.3", "description": "Multi Tenant plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-nested-docs/package.json b/packages/plugin-nested-docs/package.json index 830dda0f387..bb01d38fc2e 100644 --- a/packages/plugin-nested-docs/package.json +++ b/packages/plugin-nested-docs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-nested-docs", - "version": "3.68.2", + "version": "3.68.3", "description": "The official Nested Docs plugin for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-redirects/package.json b/packages/plugin-redirects/package.json index 7cedbae093e..45f8d5de607 100644 --- a/packages/plugin-redirects/package.json +++ b/packages/plugin-redirects/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-redirects", - "version": "3.68.2", + "version": "3.68.3", "description": "Redirects plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-search/package.json b/packages/plugin-search/package.json index fcd5df3b106..f08f5ca9947 100644 --- a/packages/plugin-search/package.json +++ b/packages/plugin-search/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-search", - "version": "3.68.2", + "version": "3.68.3", "description": "Search plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-sentry/package.json b/packages/plugin-sentry/package.json index 4d8cd08c803..ed05a3694f4 100644 --- a/packages/plugin-sentry/package.json +++ b/packages/plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-sentry", - "version": "3.68.2", + "version": "3.68.3", "description": "Sentry plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-seo/package.json b/packages/plugin-seo/package.json index eb7bf9016e0..40aba59186d 100644 --- a/packages/plugin-seo/package.json +++ b/packages/plugin-seo/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-seo", - "version": "3.68.2", + "version": "3.68.3", "description": "SEO plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-stripe/package.json b/packages/plugin-stripe/package.json index 958c4380487..9f09d905a86 100644 --- a/packages/plugin-stripe/package.json +++ b/packages/plugin-stripe/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-stripe", - "version": "3.68.2", + "version": "3.68.3", "description": "Stripe plugin for Payload", "keywords": [ "payload", diff --git a/packages/richtext-lexical/package.json b/packages/richtext-lexical/package.json index b217bab44cf..021647c04bc 100644 --- a/packages/richtext-lexical/package.json +++ b/packages/richtext-lexical/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-lexical", - "version": "3.68.2", + "version": "3.68.3", "description": "The officially supported Lexical richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/richtext-slate/package.json b/packages/richtext-slate/package.json index 38083e23c29..bbf592757fa 100644 --- a/packages/richtext-slate/package.json +++ b/packages/richtext-slate/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-slate", - "version": "3.68.2", + "version": "3.68.3", "description": "The officially supported Slate richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index c94e157ede0..aa5e74681b3 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/sdk", - "version": "3.68.2", + "version": "3.68.3", "description": "The official Payload REST API SDK", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-azure/package.json b/packages/storage-azure/package.json index b19b630f7b1..146e4b7ce99 100644 --- a/packages/storage-azure/package.json +++ b/packages/storage-azure/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-azure", - "version": "3.68.2", + "version": "3.68.3", "description": "Payload storage adapter for Azure Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-gcs/package.json b/packages/storage-gcs/package.json index 4974fd8591a..b9bf835b7ee 100644 --- a/packages/storage-gcs/package.json +++ b/packages/storage-gcs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-gcs", - "version": "3.68.2", + "version": "3.68.3", "description": "Payload storage adapter for Google Cloud Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-r2/package.json b/packages/storage-r2/package.json index 6f4692ea7ed..b8370abf6de 100644 --- a/packages/storage-r2/package.json +++ b/packages/storage-r2/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-r2", - "version": "3.68.2", + "version": "3.68.3", "description": "Payload storage adapter for Cloudflare R2", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-s3/package.json b/packages/storage-s3/package.json index 0845f64e1ac..b0b41275f5a 100644 --- a/packages/storage-s3/package.json +++ b/packages/storage-s3/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-s3", - "version": "3.68.2", + "version": "3.68.3", "description": "Payload storage adapter for Amazon S3", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-uploadthing/package.json b/packages/storage-uploadthing/package.json index 3c0d4de37e4..95f6a3fcc60 100644 --- a/packages/storage-uploadthing/package.json +++ b/packages/storage-uploadthing/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-uploadthing", - "version": "3.68.2", + "version": "3.68.3", "description": "Payload storage adapter for uploadthing", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-vercel-blob/package.json b/packages/storage-vercel-blob/package.json index dfc1e79b6ae..8d032e80cc0 100644 --- a/packages/storage-vercel-blob/package.json +++ b/packages/storage-vercel-blob/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-vercel-blob", - "version": "3.68.2", + "version": "3.68.3", "description": "Payload storage adapter for Vercel Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/translations/package.json b/packages/translations/package.json index b68b632addb..38b9a100140 100644 --- a/packages/translations/package.json +++ b/packages/translations/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/translations", - "version": "3.68.2", + "version": "3.68.3", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/ui/package.json b/packages/ui/package.json index b659acb3164..8b138b06ed4 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/ui", - "version": "3.68.2", + "version": "3.68.3", "homepage": "https://payloadcms.com", "repository": { "type": "git", From a12e48cc5bcf289c1aadc03049515444fcfb78e6 Mon Sep 17 00:00:00 2001 From: Jessica Rynkar <67977755+jessrynkar@users.noreply.github.com> Date: Fri, 12 Dec 2025 10:58:54 +0000 Subject: [PATCH 04/67] fix: previousValue from hooks should be populated within lexical blocks (#14856) ### What? Updates the `previousValue` data sent to the `afterChange` hook to accomodate **lexical nested** paths. ### Why? Currently the `afterChange` hook uses the previousDoc: ```ts previousValue: getNestedValue(previousDoc, pathSegments) ?? previousDoc?.[field.name], ``` However, with fields from within Lexical, the data on the full `previousDoc` has a complex nesting structure. In this case, we should be using the `previousSiblingDoc` to only return the sibling data and easily de-structure the data. ### How? Checks if sibling data exists, and uses it if it does: ```ts const previousValData = previousSiblingDoc && Object.keys(previousSiblingDoc).length > 0 ? previousSiblingDoc : previousDoc ``` **Reported by client.** Related PR: https://github.com/payloadcms/payload/pull/14582 --------- Co-authored-by: German Jablonski <43938777+GermanJablo@users.noreply.github.com> --- .../src/fields/hooks/afterChange/promise.ts | 9 +- .../NestedAfterChangeHook/index.ts | 65 ++++++++++- test/hooks/int.spec.ts | 105 ++++++++++++++++++ test/hooks/payload-types.ts | 16 +++ 4 files changed, 192 insertions(+), 3 deletions(-) diff --git a/packages/payload/src/fields/hooks/afterChange/promise.ts b/packages/payload/src/fields/hooks/afterChange/promise.ts index dd67284b87a..e38d17dc57e 100644 --- a/packages/payload/src/fields/hooks/afterChange/promise.ts +++ b/packages/payload/src/fields/hooks/afterChange/promise.ts @@ -72,6 +72,10 @@ export const promise = async ({ const indexPathSegments = indexPath ? indexPath.split('-').filter(Boolean)?.map(Number) : [] const getNestedValue = (data: JsonObject, path: string[]) => path.reduce((acc, key) => (acc && acc[key] !== undefined ? acc[key] : undefined), data) + const previousValData = + previousSiblingDoc && Object.keys(previousSiblingDoc).length > 0 + ? previousSiblingDoc + : previousDoc if (fieldAffectsData(field)) { // Execute hooks @@ -90,7 +94,8 @@ export const promise = async ({ path: pathSegments, previousDoc, previousSiblingDoc, - previousValue: getNestedValue(previousDoc, pathSegments) ?? previousDoc?.[field.name], + previousValue: + getNestedValue(previousValData, pathSegments) ?? previousValData?.[field.name], req, schemaPath: schemaPathSegments, siblingData, @@ -172,7 +177,7 @@ export const promise = async ({ parentPath: path + '.' + rowIndex, parentSchemaPath: schemaPath + '.' + block.slug, previousDoc, - previousSiblingDoc: previousDoc?.[field.name]?.[rowIndex] || ({} as JsonObject), + previousSiblingDoc: previousValData?.[field.name]?.[rowIndex] || ({} as JsonObject), req, siblingData: siblingData?.[field.name]?.[rowIndex] || {}, siblingDoc: row ? { ...row } : {}, diff --git a/test/hooks/collections/NestedAfterChangeHook/index.ts b/test/hooks/collections/NestedAfterChangeHook/index.ts index b61e8f7b11b..b06d27e9867 100644 --- a/test/hooks/collections/NestedAfterChangeHook/index.ts +++ b/test/hooks/collections/NestedAfterChangeHook/index.ts @@ -1,4 +1,6 @@ import type { CollectionConfig } from 'payload' + +import { BlocksFeature, lexicalEditor, LinkFeature } from '@payloadcms/richtext-lexical' export const nestedAfterChangeHooksSlug = 'nested-after-change-hooks' const NestedAfterChangeHooks: CollectionConfig = { @@ -22,7 +24,6 @@ const NestedAfterChangeHooks: CollectionConfig = { hooks: { afterChange: [ ({ previousValue, operation }) => { - console.log(previousValue) if (operation === 'update' && typeof previousValue === 'undefined') { throw new Error('previousValue is missing in nested beforeChange hook') } @@ -34,6 +35,68 @@ const NestedAfterChangeHooks: CollectionConfig = { }, ], }, + { + name: 'lexical', + type: 'richText', + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + BlocksFeature({ + blocks: [ + { + slug: 'nestedBlock', + fields: [ + { + type: 'text', + name: 'nestedAfterChange', + hooks: { + afterChange: [ + ({ previousValue, operation }) => { + if (operation === 'update' && typeof previousValue === 'undefined') { + throw new Error('previousValue is missing in nested beforeChange hook') + } + }, + ], + }, + }, + ], + }, + ], + }), + LinkFeature({ + fields: [ + { + type: 'blocks', + name: 'linkBlocks', + blocks: [ + { + slug: 'nestedLinkBlock', + fields: [ + { + name: 'nestedRelationship', + type: 'relationship', + relationTo: 'relations', + hooks: { + afterChange: [ + ({ previousValue, operation }) => { + if (operation === 'update' && typeof previousValue === 'undefined') { + throw new Error( + 'previousValue is missing in nested beforeChange hook', + ) + } + }, + ], + }, + }, + ], + }, + ], + }, + ], + }), + ], + }), + }, ], } diff --git a/test/hooks/int.spec.ts b/test/hooks/int.spec.ts index 43743465d90..122bfc8bbc9 100644 --- a/test/hooks/int.spec.ts +++ b/test/hooks/int.spec.ts @@ -368,6 +368,111 @@ describe('Hooks', () => { expect(updatedDoc).toBeDefined() }) + + it('should populate previousValue in Lexical nested afterChange hooks', async () => { + const relationID = await payload.create({ + collection: 'relations', + data: { + title: 'Relation for nested afterChange', + }, + }) + + // this collection will throw an error if previousValue is not defined in nested afterChange hook + const nestedAfterChangeDoc = await payload.create({ + collection: nestedAfterChangeHooksSlug, + data: { + text: 'initial', + group: { + array: [ + { + nestedAfterChange: 'initial', + }, + ], + }, + lexical: { + root: { + children: [ + { + children: [ + { + children: [ + { + detail: 0, + format: 0, + mode: 'normal', + style: '', + text: 'link', + type: 'text', + version: 1, + }, + ], + direction: null, + format: '', + indent: 0, + type: 'link', + version: 3, + fields: { + linkBlocks: [ + { + id: '693ade72068ea07ba13edcab', + blockType: 'nestedLinkBlock', + nestedRelationship: relationID.id, + }, + ], + }, + id: '693ade70068ea07ba13edca9', + }, + ], + direction: null, + format: '', + indent: 0, + type: 'paragraph', + version: 1, + textFormat: 0, + textStyle: '', + }, + { + type: 'block', + version: 2, + format: '', + fields: { + id: '693adf3c068ea07ba13edcae', + blockName: '', + nestedAfterChange: 'test', + blockType: 'nestedBlock', + }, + }, + { + children: [], + direction: null, + format: '', + indent: 0, + type: 'paragraph', + version: 1, + textFormat: 0, + textStyle: '', + }, + ], + direction: null, + format: '', + indent: 0, + type: 'root', + version: 1, + }, + }, + }, + }) + + await expect( + payload.update({ + collection: 'nested-after-change-hooks', + id: nestedAfterChangeDoc.id, + data: { + text: 'updated', + }, + }), + ).resolves.not.toThrow() + }) }) describe('auth collection hooks', () => { diff --git a/test/hooks/payload-types.ts b/test/hooks/payload-types.ts index ffe8b949d14..92f2eb15d7d 100644 --- a/test/hooks/payload-types.ts +++ b/test/hooks/payload-types.ts @@ -288,6 +288,21 @@ export interface NestedAfterChangeHook { }[] | null; }; + lexical?: { + root: { + type: string; + children: { + type: any; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; updatedAt: string; createdAt: string; } @@ -943,6 +958,7 @@ export interface NestedAfterChangeHooksSelect { id?: T; }; }; + lexical?: T; updatedAt?: T; createdAt?: T; } From e44d8c0578a6dedd4885c166b941b381dd7734e1 Mon Sep 17 00:00:00 2001 From: kat <143475611+puzzlesremixed@users.noreply.github.com> Date: Sat, 13 Dec 2025 03:06:53 +0700 Subject: [PATCH 05/67] docs: update collection access control reference link on collection config page (#14905) The link despite written as "Collection Access Control", currently point to the general Access Control page and not the dedicated page for Collection Access Control. On the same paragraph there's also a reference to the Access Control page and makes it confusing. This replace the link to point to the dedicated Collection Access Control page. --- docs/configuration/collections.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/collections.mdx b/docs/configuration/collections.mdx index 0eea5d52997..539a6118833 100644 --- a/docs/configuration/collections.mdx +++ b/docs/configuration/collections.mdx @@ -96,7 +96,7 @@ Fields define the schema of the Documents within a Collection. To learn more, go ### Access Control -[Collection Access Control](../access-control/overview) determines what a user can and cannot do with any given Document within a Collection. To learn more, go to the [Access Control](../access-control/overview) documentation. +[Collection Access Control](../access-control/collections) determines what a user can and cannot do with any given Document within a Collection. To learn more, go to the [Access Control](../access-control/overview) documentation. ### Hooks From 22c7badc757fc4fc75edbdee4efc8294b52210dc Mon Sep 17 00:00:00 2001 From: Aaron Claes <52576914+AaronClaes@users.noreply.github.com> Date: Fri, 12 Dec 2025 21:07:08 +0100 Subject: [PATCH 06/67] fix(ui): relationship add button unsafe permissions property access (#14903) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What? Fix crashing due to unsafe permissions property access in `AddNewRelation` by safely checking that a collection’s permissions exist before reading its `create` property. ### Why? Accessing `permissions.collections[slug].create` throws and breaks the UI when a collection’s permissions entry is missing. This happens for example when collection‑level access control makes that collection inaccessible. ### How? Change the condition to use optional chaining on the permissions, aligning with usage elsewhere in the codebase: - Before: `permissions.collections[relatedCollection?.slug].create` - After: `permissions.collections[relatedCollection?.slug]?.create` --- packages/ui/src/elements/AddNewRelation/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/elements/AddNewRelation/index.tsx b/packages/ui/src/elements/AddNewRelation/index.tsx index ef1309b157a..9c126c3d28c 100644 --- a/packages/ui/src/elements/AddNewRelation/index.tsx +++ b/packages/ui/src/elements/AddNewRelation/index.tsx @@ -193,7 +193,7 @@ export const AddNewRelation: React.FC = ({ render={({ close: closePopup }) => ( {relatedCollections.map((relatedCollection) => { - if (permissions.collections[relatedCollection?.slug].create) { + if (permissions.collections[relatedCollection?.slug]?.create) { return ( Date: Sat, 13 Dec 2025 04:28:05 +0800 Subject: [PATCH 07/67] fix(ui): show localized locale name for publish specific locale button (#14906) Use `getTranslation` for translating localized locale names. Previously, we were using the current **locale** to get the locale label i18n entry. This is incorrect - we need to use the current i18n language, which is what `getTranslation` does. Fixes https://github.com/payloadcms/payload/issues/14875 --- .../ui/src/elements/PublishButton/index.tsx | 9 ++---- test/localization/config.ts | 30 +++++++++++++++---- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/ui/src/elements/PublishButton/index.tsx b/packages/ui/src/elements/PublishButton/index.tsx index f6ad9349434..7ee3928a4b9 100644 --- a/packages/ui/src/elements/PublishButton/index.tsx +++ b/packages/ui/src/elements/PublishButton/index.tsx @@ -3,6 +3,7 @@ import type { PublishButtonClientProps } from 'payload' import { useModal } from '@faceless-ui/modal' +import { getTranslation } from '@payloadcms/translations' import { hasAutosaveEnabled, hasScheduledPublishEnabled } from 'payload/shared' import * as qs from 'qs-esm' import React, { useCallback, useEffect, useState } from 'react' @@ -49,7 +50,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { serverURL, } = config - const { t } = useTranslation() + const { i18n, t } = useTranslation() const label = labelProp || t('version:publishChanges') const entityConfig = React.useMemo(() => { @@ -197,11 +198,7 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { typeof locale === 'string' ? locale === localeCode : locale.code === localeCode, ) - const activeLocaleLabel = - activeLocale && - (typeof activeLocale.label === 'string' - ? activeLocale.label - : (activeLocale.label?.[localeCode] ?? undefined)) + const activeLocaleLabel = activeLocale && getTranslation(activeLocale.label, i18n) if (!hasPublishPermission) { return null diff --git a/test/localization/config.ts b/test/localization/config.ts index 85ad95dd562..ac99dc5084c 100644 --- a/test/localization/config.ts +++ b/test/localization/config.ts @@ -443,27 +443,47 @@ export default buildConfigWithDefaults({ }, { code: defaultLocale, - label: 'English', + label: { + de: 'Englisch', + en: 'English', + es: 'Inglés', + }, rtl: false, }, { code: spanishLocale, - label: 'Spanish', + label: { + de: 'Spanisch', + en: 'Spanish', + es: 'Español', + }, rtl: false, }, { code: portugueseLocale, fallbackLocale: spanishLocale, - label: 'Portuguese', + label: { + de: 'Portugiesisch', + en: 'Portuguese', + es: 'Portugués', + }, }, { code: 'ar', - label: 'Arabic', + label: { + de: 'Arabisch', + en: 'Arabic', + es: 'Árabe', + }, rtl: true, }, { code: hungarianLocale, - label: 'Hungarian', + label: { + de: 'Ungarische', + en: 'Hungarian', + es: 'Húngaro', + }, rtl: false, }, ], From dac0f20eeab9cc206a4bb80cc6a632c52674dd1d Mon Sep 17 00:00:00 2001 From: Riley Langbein <54197972+rilrom@users.noreply.github.com> Date: Sat, 13 Dec 2025 15:27:51 +1030 Subject: [PATCH 08/67] docs: remove unused variable from custom field label translation (#14911) ### What? There is an unused variable in one of the i18n custom translation examples. ### Why? Improve overall readability of documentation. ### How? Remove the unused variable. --- docs/configuration/i18n.mdx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/configuration/i18n.mdx b/docs/configuration/i18n.mdx index ea5ad73c90b..ee3b9111896 100644 --- a/docs/configuration/i18n.mdx +++ b/docs/configuration/i18n.mdx @@ -262,10 +262,7 @@ Additionally, Payload exposes the `t` function in various places, for example in ```ts // /fields/myField.ts -import type { - DefaultTranslationKeys, - TFunction, -} from '@payloadcms/translations' +import type { TFunction } from '@payloadcms/translations' import type { Field } from 'payload' import { CustomTranslationsKeys } from '../custom-translations' From e24e12228432f4eb1a72f11a644273251af1b14f Mon Sep 17 00:00:00 2001 From: Jake Date: Sun, 14 Dec 2025 09:56:00 -0500 Subject: [PATCH 09/67] fix(next): properly construct local req url (#14907) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/payloadcms/payload/issues/14900. Supersedes https://github.com/payloadcms/payload/pull/14901. Since https://github.com/payloadcms/payload/pull/14869, loading the admin panel with a `serverURL` crashes with the following error: ``` ⨯ [TypeError: Invalid URL] { code: 'ERR_INVALID_URL', input: 'http://localhost:3000http://localhost:3000/admin', digest: '185251315' } [12:26:08] ERROR: Failed to create URL object from URL: http://localhost:3000http://localhost:3000/admin, falling back to http://localhost:3000http://localhost:3000/admin ``` This is because the suffix used to create a local req object was changed to include the server URL. As the name implies, it should be a relative path that appends onto the base URL. --- .github/workflows/main.yml | 1 + packages/next/src/views/NotFound/index.tsx | 4 +- packages/next/src/views/Root/index.tsx | 7 +- test/server-url/.gitignore | 2 + test/server-url/config.ts | 31 + test/server-url/e2e.spec.ts | 35 + test/server-url/payload-types.ts | 450 +++ test/server-url/schema.graphql | 4271 ++++++++++++++++++++ test/server-url/tsconfig.eslint.json | 13 + test/server-url/tsconfig.json | 3 + test/server-url/types.d.ts | 9 + 11 files changed, 4824 insertions(+), 2 deletions(-) create mode 100644 test/server-url/.gitignore create mode 100644 test/server-url/config.ts create mode 100644 test/server-url/e2e.spec.ts create mode 100644 test/server-url/payload-types.ts create mode 100644 test/server-url/schema.graphql create mode 100644 test/server-url/tsconfig.eslint.json create mode 100644 test/server-url/tsconfig.json create mode 100644 test/server-url/types.d.ts diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 56a129bb99b..330087571a0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -326,6 +326,7 @@ jobs: - plugin-redirects - plugin-seo - sort + - server-url - trash - versions - uploads diff --git a/packages/next/src/views/NotFound/index.tsx b/packages/next/src/views/NotFound/index.tsx index ee033f235a5..72d3e9aaa5a 100644 --- a/packages/next/src/views/NotFound/index.tsx +++ b/packages/next/src/views/NotFound/index.tsx @@ -48,6 +48,7 @@ export const NotFoundPage = async ({ const searchParams = await searchParamsPromise const queryString = `${qs.stringify(searchParams ?? {}, { addQueryPrefix: true })}` + const { locale, permissions, @@ -65,7 +66,8 @@ export const NotFoundPage = async ({ ignoreQueryPrefix: true, }), }, - urlSuffix: `${formatAdminURL({ adminRoute, path: '/not-found', serverURL: config.serverURL })}${searchParams ? queryString : ''}`, + // intentionally omit `serverURL` to keep URL relative + urlSuffix: `${formatAdminURL({ adminRoute, path: '/not-found' })}${searchParams ? queryString : ''}`, }, }) diff --git a/packages/next/src/views/Root/index.tsx b/packages/next/src/views/Root/index.tsx index 4deb4ea1b43..a00bef04870 100644 --- a/packages/next/src/views/Root/index.tsx +++ b/packages/next/src/views/Root/index.tsx @@ -120,6 +120,7 @@ export const RootPage = async ({ } const queryString = `${qs.stringify(searchParams ?? {}, { addQueryPrefix: true })}` + const { cookies, locale, @@ -138,7 +139,11 @@ export const RootPage = async ({ ignoreQueryPrefix: true, }), }, - urlSuffix: `${currentRoute}${searchParams ? queryString : ''}`, + // intentionally omit `serverURL` to keep URL relative + urlSuffix: `${formatAdminURL({ + adminRoute, + path: Array.isArray(params.segments) ? `/${params.segments.join('/')}` : null, + })}${searchParams ? queryString : ''}`, }, }) diff --git a/test/server-url/.gitignore b/test/server-url/.gitignore new file mode 100644 index 00000000000..cce01755f4f --- /dev/null +++ b/test/server-url/.gitignore @@ -0,0 +1,2 @@ +/media +/media-gif diff --git a/test/server-url/config.ts b/test/server-url/config.ts new file mode 100644 index 00000000000..e0903b91343 --- /dev/null +++ b/test/server-url/config.ts @@ -0,0 +1,31 @@ +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { fileURLToPath } from 'node:url' +import path from 'path' + +import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' +import { devUser } from '../credentials.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfigWithDefaults({ + serverURL: 'http://localhost:3000', + admin: { + importMap: { + baseDir: path.resolve(dirname), + }, + }, + editor: lexicalEditor({}), + onInit: async (payload) => { + await payload.create({ + collection: 'users', + data: { + email: devUser.email, + password: devUser.password, + }, + }) + }, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, +}) diff --git a/test/server-url/e2e.spec.ts b/test/server-url/e2e.spec.ts new file mode 100644 index 00000000000..19d8be8b9a2 --- /dev/null +++ b/test/server-url/e2e.spec.ts @@ -0,0 +1,35 @@ +import type { Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import * as path from 'path' +import { fileURLToPath } from 'url' + +import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' +import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' +import { TEST_TIMEOUT_LONG } from '../playwright.config.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +test.describe('serverURL', () => { + let page: Page + let url: AdminUrlUtil + + test.beforeAll(async ({ browser }, testInfo) => { + testInfo.setTimeout(TEST_TIMEOUT_LONG) + + const { payload, serverURL } = await initPayloadE2ENoConfig({ dirname }) + url = new AdminUrlUtil(serverURL, 'posts') + + const context = await browser.newContext() + page = await context.newPage() + initPageConsoleErrorCatch(page) + await ensureCompilationIsDone({ page, serverURL }) + }) + + test('can load admin panel when serverURL is set', async () => { + await page.goto(url.admin) + await expect(page.getByText('Dashboard')).toBeVisible() + }) +}) diff --git a/test/server-url/payload-types.ts b/test/server-url/payload-types.ts new file mode 100644 index 00000000000..39b48742beb --- /dev/null +++ b/test/server-url/payload-types.ts @@ -0,0 +1,450 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * This file was automatically generated by Payload. + * DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config, + * and re-run `payload generate:types` to regenerate this file. + */ + +/** + * Supported timezones in IANA format. + * + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "supportedTimezones". + */ +export type SupportedTimezones = + | 'Pacific/Midway' + | 'Pacific/Niue' + | 'Pacific/Honolulu' + | 'Pacific/Rarotonga' + | 'America/Anchorage' + | 'Pacific/Gambier' + | 'America/Los_Angeles' + | 'America/Tijuana' + | 'America/Denver' + | 'America/Phoenix' + | 'America/Chicago' + | 'America/Guatemala' + | 'America/New_York' + | 'America/Bogota' + | 'America/Caracas' + | 'America/Santiago' + | 'America/Buenos_Aires' + | 'America/Sao_Paulo' + | 'Atlantic/South_Georgia' + | 'Atlantic/Azores' + | 'Atlantic/Cape_Verde' + | 'Europe/London' + | 'Europe/Berlin' + | 'Africa/Lagos' + | 'Europe/Athens' + | 'Africa/Cairo' + | 'Europe/Moscow' + | 'Asia/Riyadh' + | 'Asia/Dubai' + | 'Asia/Baku' + | 'Asia/Karachi' + | 'Asia/Tashkent' + | 'Asia/Calcutta' + | 'Asia/Dhaka' + | 'Asia/Almaty' + | 'Asia/Jakarta' + | 'Asia/Bangkok' + | 'Asia/Shanghai' + | 'Asia/Singapore' + | 'Asia/Tokyo' + | 'Asia/Seoul' + | 'Australia/Brisbane' + | 'Australia/Sydney' + | 'Pacific/Guam' + | 'Pacific/Noumea' + | 'Pacific/Auckland' + | 'Pacific/Fiji'; + +export interface Config { + auth: { + users: UserAuthOperations; + }; + blocks: {}; + collections: { + posts: Post; + media: Media; + 'payload-kv': PayloadKv; + users: User; + 'payload-locked-documents': PayloadLockedDocument; + 'payload-preferences': PayloadPreference; + 'payload-migrations': PayloadMigration; + }; + collectionsJoins: {}; + collectionsSelect: { + posts: PostsSelect | PostsSelect; + media: MediaSelect | MediaSelect; + 'payload-kv': PayloadKvSelect | PayloadKvSelect; + users: UsersSelect | UsersSelect; + 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; + 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; + 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; + }; + db: { + defaultIDType: string; + }; + globals: { + menu: Menu; + }; + globalsSelect: { + menu: MenuSelect | MenuSelect; + }; + locale: null; + user: User & { + collection: 'users'; + }; + jobs: { + tasks: unknown; + workflows: unknown; + }; +} +export interface UserAuthOperations { + forgotPassword: { + email: string; + password: string; + }; + login: { + email: string; + password: string; + }; + registerFirstUser: { + email: string; + password: string; + }; + unlock: { + email: string; + password: string; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "posts". + */ +export interface Post { + id: string; + title?: string | null; + content?: { + root: { + type: string; + children: { + type: any; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "media". + */ +export interface Media { + id: string; + updatedAt: string; + createdAt: string; + url?: string | null; + thumbnailURL?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + focalX?: number | null; + focalY?: number | null; + sizes?: { + thumbnail?: { + url?: string | null; + width?: number | null; + height?: number | null; + mimeType?: string | null; + filesize?: number | null; + filename?: string | null; + }; + medium?: { + url?: string | null; + width?: number | null; + height?: number | null; + mimeType?: string | null; + filesize?: number | null; + filename?: string | null; + }; + large?: { + url?: string | null; + width?: number | null; + height?: number | null; + mimeType?: string | null; + filesize?: number | null; + filename?: string | null; + }; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv". + */ +export interface PayloadKv { + id: string; + key: string; + data: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "users". + */ +export interface User { + id: string; + updatedAt: string; + createdAt: string; + email: string; + resetPasswordToken?: string | null; + resetPasswordExpiration?: string | null; + salt?: string | null; + hash?: string | null; + loginAttempts?: number | null; + lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; + password?: string | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-locked-documents". + */ +export interface PayloadLockedDocument { + id: string; + document?: + | ({ + relationTo: 'posts'; + value: string | Post; + } | null) + | ({ + relationTo: 'media'; + value: string | Media; + } | null) + | ({ + relationTo: 'users'; + value: string | User; + } | null); + globalSlug?: string | null; + user: { + relationTo: 'users'; + value: string | User; + }; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences". + */ +export interface PayloadPreference { + id: string; + user: { + relationTo: 'users'; + value: string | User; + }; + key?: string | null; + value?: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations". + */ +export interface PayloadMigration { + id: string; + name?: string | null; + batch?: number | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "posts_select". + */ +export interface PostsSelect { + title?: T; + content?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "media_select". + */ +export interface MediaSelect { + updatedAt?: T; + createdAt?: T; + url?: T; + thumbnailURL?: T; + filename?: T; + mimeType?: T; + filesize?: T; + width?: T; + height?: T; + focalX?: T; + focalY?: T; + sizes?: + | T + | { + thumbnail?: + | T + | { + url?: T; + width?: T; + height?: T; + mimeType?: T; + filesize?: T; + filename?: T; + }; + medium?: + | T + | { + url?: T; + width?: T; + height?: T; + mimeType?: T; + filesize?: T; + filename?: T; + }; + large?: + | T + | { + url?: T; + width?: T; + height?: T; + mimeType?: T; + filesize?: T; + filename?: T; + }; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv_select". + */ +export interface PayloadKvSelect { + key?: T; + data?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "users_select". + */ +export interface UsersSelect { + updatedAt?: T; + createdAt?: T; + email?: T; + resetPasswordToken?: T; + resetPasswordExpiration?: T; + salt?: T; + hash?: T; + loginAttempts?: T; + lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-locked-documents_select". + */ +export interface PayloadLockedDocumentsSelect { + document?: T; + globalSlug?: T; + user?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-preferences_select". + */ +export interface PayloadPreferencesSelect { + user?: T; + key?: T; + value?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-migrations_select". + */ +export interface PayloadMigrationsSelect { + name?: T; + batch?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "menu". + */ +export interface Menu { + id: string; + globalText?: string | null; + updatedAt?: string | null; + createdAt?: string | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "menu_select". + */ +export interface MenuSelect { + globalText?: T; + updatedAt?: T; + createdAt?: T; + globalType?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "auth". + */ +export interface Auth { + [k: string]: unknown; +} + + +declare module 'payload' { + // @ts-ignore + export interface GeneratedTypes extends Config {} +} \ No newline at end of file diff --git a/test/server-url/schema.graphql b/test/server-url/schema.graphql new file mode 100644 index 00000000000..c35db21ee73 --- /dev/null +++ b/test/server-url/schema.graphql @@ -0,0 +1,4271 @@ +type Query { + Post(id: String!, draft: Boolean): Post + Posts(draft: Boolean, where: Post_where, limit: Int, page: Int, pagination: Boolean, sort: String): Posts + countPosts(draft: Boolean, where: Post_where): countPosts + docAccessPost(id: String!): postsDocAccess + Media(id: String!, draft: Boolean): Media + allMedia(draft: Boolean, where: Media_where, limit: Int, page: Int, pagination: Boolean, sort: String): allMedia + countallMedia(draft: Boolean, where: Media_where): countallMedia + docAccessMedia(id: String!): mediaDocAccess + User(id: String!, draft: Boolean): User + Users(draft: Boolean, where: User_where, limit: Int, page: Int, pagination: Boolean, sort: String): Users + countUsers(draft: Boolean, where: User_where): countUsers + docAccessUser(id: String!): usersDocAccess + meUser: usersMe + initializedUser: Boolean + PayloadLockedDocument(id: String!, draft: Boolean): PayloadLockedDocument + PayloadLockedDocuments(draft: Boolean, where: PayloadLockedDocument_where, limit: Int, page: Int, pagination: Boolean, sort: String): PayloadLockedDocuments + countPayloadLockedDocuments(draft: Boolean, where: PayloadLockedDocument_where): countPayloadLockedDocuments + docAccessPayloadLockedDocument(id: String!): payload_locked_documentsDocAccess + PayloadPreference(id: String!, draft: Boolean): PayloadPreference + PayloadPreferences(draft: Boolean, where: PayloadPreference_where, limit: Int, page: Int, pagination: Boolean, sort: String): PayloadPreferences + countPayloadPreferences(draft: Boolean, where: PayloadPreference_where): countPayloadPreferences + docAccessPayloadPreference(id: String!): payload_preferencesDocAccess + Menu(draft: Boolean): Menu + docAccessMenu: menuDocAccess + Access: Access +} + +type Post { + id: String! + title: String + content(depth: Int): JSON + updatedAt: DateTime + createdAt: DateTime +} + +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSON @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") + +""" +A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar. +""" +scalar DateTime + +type Posts { + docs: [Post!]! + hasNextPage: Boolean! + hasPrevPage: Boolean! + limit: Int! + nextPage: Int! + offset: Int + page: Int! + pagingCounter: Int! + prevPage: Int! + totalDocs: Int! + totalPages: Int! +} + +input Post_where { + title: Post_title_operator + content: Post_content_operator + updatedAt: Post_updatedAt_operator + createdAt: Post_createdAt_operator + id: Post_id_operator + AND: [Post_where_and] + OR: [Post_where_or] +} + +input Post_title_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Post_content_operator { + equals: JSON + not_equals: JSON + like: JSON + contains: JSON + exists: Boolean +} + +input Post_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input Post_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input Post_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Post_where_and { + title: Post_title_operator + content: Post_content_operator + updatedAt: Post_updatedAt_operator + createdAt: Post_createdAt_operator + id: Post_id_operator + AND: [Post_where_and] + OR: [Post_where_or] +} + +input Post_where_or { + title: Post_title_operator + content: Post_content_operator + updatedAt: Post_updatedAt_operator + createdAt: Post_createdAt_operator + id: Post_id_operator + AND: [Post_where_and] + OR: [Post_where_or] +} + +type countPosts { + totalDocs: Int +} + +type postsDocAccess { + fields: PostsDocAccessFields + create: PostsCreateDocAccess + read: PostsReadDocAccess + update: PostsUpdateDocAccess + delete: PostsDeleteDocAccess +} + +type PostsDocAccessFields { + title: PostsDocAccessFields_title + content: PostsDocAccessFields_content + updatedAt: PostsDocAccessFields_updatedAt + createdAt: PostsDocAccessFields_createdAt +} + +type PostsDocAccessFields_title { + create: PostsDocAccessFields_title_Create + read: PostsDocAccessFields_title_Read + update: PostsDocAccessFields_title_Update + delete: PostsDocAccessFields_title_Delete +} + +type PostsDocAccessFields_title_Create { + permission: Boolean! +} + +type PostsDocAccessFields_title_Read { + permission: Boolean! +} + +type PostsDocAccessFields_title_Update { + permission: Boolean! +} + +type PostsDocAccessFields_title_Delete { + permission: Boolean! +} + +type PostsDocAccessFields_content { + create: PostsDocAccessFields_content_Create + read: PostsDocAccessFields_content_Read + update: PostsDocAccessFields_content_Update + delete: PostsDocAccessFields_content_Delete +} + +type PostsDocAccessFields_content_Create { + permission: Boolean! +} + +type PostsDocAccessFields_content_Read { + permission: Boolean! +} + +type PostsDocAccessFields_content_Update { + permission: Boolean! +} + +type PostsDocAccessFields_content_Delete { + permission: Boolean! +} + +type PostsDocAccessFields_updatedAt { + create: PostsDocAccessFields_updatedAt_Create + read: PostsDocAccessFields_updatedAt_Read + update: PostsDocAccessFields_updatedAt_Update + delete: PostsDocAccessFields_updatedAt_Delete +} + +type PostsDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PostsDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PostsDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PostsDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PostsDocAccessFields_createdAt { + create: PostsDocAccessFields_createdAt_Create + read: PostsDocAccessFields_createdAt_Read + update: PostsDocAccessFields_createdAt_Update + delete: PostsDocAccessFields_createdAt_Delete +} + +type PostsDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PostsDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PostsDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PostsDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PostsCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +""" +The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). +""" +scalar JSONObject @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") + +type PostsReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PostsUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PostsDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type Media { + id: String! + updatedAt: DateTime + createdAt: DateTime + url: String + thumbnailURL: String + filename: String + mimeType: String + filesize: Float + width: Float + height: Float + focalX: Float + focalY: Float + sizes: Media_Sizes +} + +type Media_Sizes { + thumbnail: Media_Sizes_Thumbnail + medium: Media_Sizes_Medium + large: Media_Sizes_Large +} + +type Media_Sizes_Thumbnail { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +type Media_Sizes_Medium { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +type Media_Sizes_Large { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +type allMedia { + docs: [Media!]! + hasNextPage: Boolean! + hasPrevPage: Boolean! + limit: Int! + nextPage: Int! + offset: Int + page: Int! + pagingCounter: Int! + prevPage: Int! + totalDocs: Int! + totalPages: Int! +} + +input Media_where { + updatedAt: Media_updatedAt_operator + createdAt: Media_createdAt_operator + url: Media_url_operator + thumbnailURL: Media_thumbnailURL_operator + filename: Media_filename_operator + mimeType: Media_mimeType_operator + filesize: Media_filesize_operator + width: Media_width_operator + height: Media_height_operator + focalX: Media_focalX_operator + focalY: Media_focalY_operator + sizes__thumbnail__url: Media_sizes__thumbnail__url_operator + sizes__thumbnail__width: Media_sizes__thumbnail__width_operator + sizes__thumbnail__height: Media_sizes__thumbnail__height_operator + sizes__thumbnail__mimeType: Media_sizes__thumbnail__mimeType_operator + sizes__thumbnail__filesize: Media_sizes__thumbnail__filesize_operator + sizes__thumbnail__filename: Media_sizes__thumbnail__filename_operator + sizes__medium__url: Media_sizes__medium__url_operator + sizes__medium__width: Media_sizes__medium__width_operator + sizes__medium__height: Media_sizes__medium__height_operator + sizes__medium__mimeType: Media_sizes__medium__mimeType_operator + sizes__medium__filesize: Media_sizes__medium__filesize_operator + sizes__medium__filename: Media_sizes__medium__filename_operator + sizes__large__url: Media_sizes__large__url_operator + sizes__large__width: Media_sizes__large__width_operator + sizes__large__height: Media_sizes__large__height_operator + sizes__large__mimeType: Media_sizes__large__mimeType_operator + sizes__large__filesize: Media_sizes__large__filesize_operator + sizes__large__filename: Media_sizes__large__filename_operator + id: Media_id_operator + AND: [Media_where_and] + OR: [Media_where_or] +} + +input Media_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input Media_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input Media_url_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_thumbnailURL_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_filename_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_mimeType_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_filesize_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_width_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_height_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_focalX_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_focalY_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__thumbnail__url_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__thumbnail__width_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__thumbnail__height_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__thumbnail__mimeType_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__thumbnail__filesize_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__thumbnail__filename_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__medium__url_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__medium__width_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__medium__height_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__medium__mimeType_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__medium__filesize_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__medium__filename_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__large__url_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__large__width_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__large__height_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__large__mimeType_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_sizes__large__filesize_operator { + equals: Float + not_equals: Float + greater_than_equal: Float + greater_than: Float + less_than_equal: Float + less_than: Float + exists: Boolean +} + +input Media_sizes__large__filename_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input Media_where_and { + updatedAt: Media_updatedAt_operator + createdAt: Media_createdAt_operator + url: Media_url_operator + thumbnailURL: Media_thumbnailURL_operator + filename: Media_filename_operator + mimeType: Media_mimeType_operator + filesize: Media_filesize_operator + width: Media_width_operator + height: Media_height_operator + focalX: Media_focalX_operator + focalY: Media_focalY_operator + sizes__thumbnail__url: Media_sizes__thumbnail__url_operator + sizes__thumbnail__width: Media_sizes__thumbnail__width_operator + sizes__thumbnail__height: Media_sizes__thumbnail__height_operator + sizes__thumbnail__mimeType: Media_sizes__thumbnail__mimeType_operator + sizes__thumbnail__filesize: Media_sizes__thumbnail__filesize_operator + sizes__thumbnail__filename: Media_sizes__thumbnail__filename_operator + sizes__medium__url: Media_sizes__medium__url_operator + sizes__medium__width: Media_sizes__medium__width_operator + sizes__medium__height: Media_sizes__medium__height_operator + sizes__medium__mimeType: Media_sizes__medium__mimeType_operator + sizes__medium__filesize: Media_sizes__medium__filesize_operator + sizes__medium__filename: Media_sizes__medium__filename_operator + sizes__large__url: Media_sizes__large__url_operator + sizes__large__width: Media_sizes__large__width_operator + sizes__large__height: Media_sizes__large__height_operator + sizes__large__mimeType: Media_sizes__large__mimeType_operator + sizes__large__filesize: Media_sizes__large__filesize_operator + sizes__large__filename: Media_sizes__large__filename_operator + id: Media_id_operator + AND: [Media_where_and] + OR: [Media_where_or] +} + +input Media_where_or { + updatedAt: Media_updatedAt_operator + createdAt: Media_createdAt_operator + url: Media_url_operator + thumbnailURL: Media_thumbnailURL_operator + filename: Media_filename_operator + mimeType: Media_mimeType_operator + filesize: Media_filesize_operator + width: Media_width_operator + height: Media_height_operator + focalX: Media_focalX_operator + focalY: Media_focalY_operator + sizes__thumbnail__url: Media_sizes__thumbnail__url_operator + sizes__thumbnail__width: Media_sizes__thumbnail__width_operator + sizes__thumbnail__height: Media_sizes__thumbnail__height_operator + sizes__thumbnail__mimeType: Media_sizes__thumbnail__mimeType_operator + sizes__thumbnail__filesize: Media_sizes__thumbnail__filesize_operator + sizes__thumbnail__filename: Media_sizes__thumbnail__filename_operator + sizes__medium__url: Media_sizes__medium__url_operator + sizes__medium__width: Media_sizes__medium__width_operator + sizes__medium__height: Media_sizes__medium__height_operator + sizes__medium__mimeType: Media_sizes__medium__mimeType_operator + sizes__medium__filesize: Media_sizes__medium__filesize_operator + sizes__medium__filename: Media_sizes__medium__filename_operator + sizes__large__url: Media_sizes__large__url_operator + sizes__large__width: Media_sizes__large__width_operator + sizes__large__height: Media_sizes__large__height_operator + sizes__large__mimeType: Media_sizes__large__mimeType_operator + sizes__large__filesize: Media_sizes__large__filesize_operator + sizes__large__filename: Media_sizes__large__filename_operator + id: Media_id_operator + AND: [Media_where_and] + OR: [Media_where_or] +} + +type countallMedia { + totalDocs: Int +} + +type mediaDocAccess { + fields: MediaDocAccessFields + create: MediaCreateDocAccess + read: MediaReadDocAccess + update: MediaUpdateDocAccess + delete: MediaDeleteDocAccess +} + +type MediaDocAccessFields { + updatedAt: MediaDocAccessFields_updatedAt + createdAt: MediaDocAccessFields_createdAt + url: MediaDocAccessFields_url + thumbnailURL: MediaDocAccessFields_thumbnailURL + filename: MediaDocAccessFields_filename + mimeType: MediaDocAccessFields_mimeType + filesize: MediaDocAccessFields_filesize + width: MediaDocAccessFields_width + height: MediaDocAccessFields_height + focalX: MediaDocAccessFields_focalX + focalY: MediaDocAccessFields_focalY + sizes: MediaDocAccessFields_sizes +} + +type MediaDocAccessFields_updatedAt { + create: MediaDocAccessFields_updatedAt_Create + read: MediaDocAccessFields_updatedAt_Read + update: MediaDocAccessFields_updatedAt_Update + delete: MediaDocAccessFields_updatedAt_Delete +} + +type MediaDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type MediaDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type MediaDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type MediaDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_createdAt { + create: MediaDocAccessFields_createdAt_Create + read: MediaDocAccessFields_createdAt_Read + update: MediaDocAccessFields_createdAt_Update + delete: MediaDocAccessFields_createdAt_Delete +} + +type MediaDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type MediaDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type MediaDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type MediaDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_url { + create: MediaDocAccessFields_url_Create + read: MediaDocAccessFields_url_Read + update: MediaDocAccessFields_url_Update + delete: MediaDocAccessFields_url_Delete +} + +type MediaDocAccessFields_url_Create { + permission: Boolean! +} + +type MediaDocAccessFields_url_Read { + permission: Boolean! +} + +type MediaDocAccessFields_url_Update { + permission: Boolean! +} + +type MediaDocAccessFields_url_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_thumbnailURL { + create: MediaDocAccessFields_thumbnailURL_Create + read: MediaDocAccessFields_thumbnailURL_Read + update: MediaDocAccessFields_thumbnailURL_Update + delete: MediaDocAccessFields_thumbnailURL_Delete +} + +type MediaDocAccessFields_thumbnailURL_Create { + permission: Boolean! +} + +type MediaDocAccessFields_thumbnailURL_Read { + permission: Boolean! +} + +type MediaDocAccessFields_thumbnailURL_Update { + permission: Boolean! +} + +type MediaDocAccessFields_thumbnailURL_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_filename { + create: MediaDocAccessFields_filename_Create + read: MediaDocAccessFields_filename_Read + update: MediaDocAccessFields_filename_Update + delete: MediaDocAccessFields_filename_Delete +} + +type MediaDocAccessFields_filename_Create { + permission: Boolean! +} + +type MediaDocAccessFields_filename_Read { + permission: Boolean! +} + +type MediaDocAccessFields_filename_Update { + permission: Boolean! +} + +type MediaDocAccessFields_filename_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_mimeType { + create: MediaDocAccessFields_mimeType_Create + read: MediaDocAccessFields_mimeType_Read + update: MediaDocAccessFields_mimeType_Update + delete: MediaDocAccessFields_mimeType_Delete +} + +type MediaDocAccessFields_mimeType_Create { + permission: Boolean! +} + +type MediaDocAccessFields_mimeType_Read { + permission: Boolean! +} + +type MediaDocAccessFields_mimeType_Update { + permission: Boolean! +} + +type MediaDocAccessFields_mimeType_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_filesize { + create: MediaDocAccessFields_filesize_Create + read: MediaDocAccessFields_filesize_Read + update: MediaDocAccessFields_filesize_Update + delete: MediaDocAccessFields_filesize_Delete +} + +type MediaDocAccessFields_filesize_Create { + permission: Boolean! +} + +type MediaDocAccessFields_filesize_Read { + permission: Boolean! +} + +type MediaDocAccessFields_filesize_Update { + permission: Boolean! +} + +type MediaDocAccessFields_filesize_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_width { + create: MediaDocAccessFields_width_Create + read: MediaDocAccessFields_width_Read + update: MediaDocAccessFields_width_Update + delete: MediaDocAccessFields_width_Delete +} + +type MediaDocAccessFields_width_Create { + permission: Boolean! +} + +type MediaDocAccessFields_width_Read { + permission: Boolean! +} + +type MediaDocAccessFields_width_Update { + permission: Boolean! +} + +type MediaDocAccessFields_width_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_height { + create: MediaDocAccessFields_height_Create + read: MediaDocAccessFields_height_Read + update: MediaDocAccessFields_height_Update + delete: MediaDocAccessFields_height_Delete +} + +type MediaDocAccessFields_height_Create { + permission: Boolean! +} + +type MediaDocAccessFields_height_Read { + permission: Boolean! +} + +type MediaDocAccessFields_height_Update { + permission: Boolean! +} + +type MediaDocAccessFields_height_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_focalX { + create: MediaDocAccessFields_focalX_Create + read: MediaDocAccessFields_focalX_Read + update: MediaDocAccessFields_focalX_Update + delete: MediaDocAccessFields_focalX_Delete +} + +type MediaDocAccessFields_focalX_Create { + permission: Boolean! +} + +type MediaDocAccessFields_focalX_Read { + permission: Boolean! +} + +type MediaDocAccessFields_focalX_Update { + permission: Boolean! +} + +type MediaDocAccessFields_focalX_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_focalY { + create: MediaDocAccessFields_focalY_Create + read: MediaDocAccessFields_focalY_Read + update: MediaDocAccessFields_focalY_Update + delete: MediaDocAccessFields_focalY_Delete +} + +type MediaDocAccessFields_focalY_Create { + permission: Boolean! +} + +type MediaDocAccessFields_focalY_Read { + permission: Boolean! +} + +type MediaDocAccessFields_focalY_Update { + permission: Boolean! +} + +type MediaDocAccessFields_focalY_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes { + create: MediaDocAccessFields_sizes_Create + read: MediaDocAccessFields_sizes_Read + update: MediaDocAccessFields_sizes_Update + delete: MediaDocAccessFields_sizes_Delete + fields: MediaDocAccessFields_sizes_Fields +} + +type MediaDocAccessFields_sizes_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_Fields { + thumbnail: MediaDocAccessFields_sizes_thumbnail + medium: MediaDocAccessFields_sizes_medium + large: MediaDocAccessFields_sizes_large +} + +type MediaDocAccessFields_sizes_thumbnail { + create: MediaDocAccessFields_sizes_thumbnail_Create + read: MediaDocAccessFields_sizes_thumbnail_Read + update: MediaDocAccessFields_sizes_thumbnail_Update + delete: MediaDocAccessFields_sizes_thumbnail_Delete + fields: MediaDocAccessFields_sizes_thumbnail_Fields +} + +type MediaDocAccessFields_sizes_thumbnail_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_Fields { + url: MediaDocAccessFields_sizes_thumbnail_url + width: MediaDocAccessFields_sizes_thumbnail_width + height: MediaDocAccessFields_sizes_thumbnail_height + mimeType: MediaDocAccessFields_sizes_thumbnail_mimeType + filesize: MediaDocAccessFields_sizes_thumbnail_filesize + filename: MediaDocAccessFields_sizes_thumbnail_filename +} + +type MediaDocAccessFields_sizes_thumbnail_url { + create: MediaDocAccessFields_sizes_thumbnail_url_Create + read: MediaDocAccessFields_sizes_thumbnail_url_Read + update: MediaDocAccessFields_sizes_thumbnail_url_Update + delete: MediaDocAccessFields_sizes_thumbnail_url_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_url_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_url_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_url_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_url_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_width { + create: MediaDocAccessFields_sizes_thumbnail_width_Create + read: MediaDocAccessFields_sizes_thumbnail_width_Read + update: MediaDocAccessFields_sizes_thumbnail_width_Update + delete: MediaDocAccessFields_sizes_thumbnail_width_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_width_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_width_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_width_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_width_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_height { + create: MediaDocAccessFields_sizes_thumbnail_height_Create + read: MediaDocAccessFields_sizes_thumbnail_height_Read + update: MediaDocAccessFields_sizes_thumbnail_height_Update + delete: MediaDocAccessFields_sizes_thumbnail_height_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_height_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_height_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_height_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_height_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_mimeType { + create: MediaDocAccessFields_sizes_thumbnail_mimeType_Create + read: MediaDocAccessFields_sizes_thumbnail_mimeType_Read + update: MediaDocAccessFields_sizes_thumbnail_mimeType_Update + delete: MediaDocAccessFields_sizes_thumbnail_mimeType_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_mimeType_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_mimeType_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_mimeType_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_mimeType_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filesize { + create: MediaDocAccessFields_sizes_thumbnail_filesize_Create + read: MediaDocAccessFields_sizes_thumbnail_filesize_Read + update: MediaDocAccessFields_sizes_thumbnail_filesize_Update + delete: MediaDocAccessFields_sizes_thumbnail_filesize_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_filesize_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filesize_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filesize_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filesize_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filename { + create: MediaDocAccessFields_sizes_thumbnail_filename_Create + read: MediaDocAccessFields_sizes_thumbnail_filename_Read + update: MediaDocAccessFields_sizes_thumbnail_filename_Update + delete: MediaDocAccessFields_sizes_thumbnail_filename_Delete +} + +type MediaDocAccessFields_sizes_thumbnail_filename_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filename_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filename_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_thumbnail_filename_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium { + create: MediaDocAccessFields_sizes_medium_Create + read: MediaDocAccessFields_sizes_medium_Read + update: MediaDocAccessFields_sizes_medium_Update + delete: MediaDocAccessFields_sizes_medium_Delete + fields: MediaDocAccessFields_sizes_medium_Fields +} + +type MediaDocAccessFields_sizes_medium_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_Fields { + url: MediaDocAccessFields_sizes_medium_url + width: MediaDocAccessFields_sizes_medium_width + height: MediaDocAccessFields_sizes_medium_height + mimeType: MediaDocAccessFields_sizes_medium_mimeType + filesize: MediaDocAccessFields_sizes_medium_filesize + filename: MediaDocAccessFields_sizes_medium_filename +} + +type MediaDocAccessFields_sizes_medium_url { + create: MediaDocAccessFields_sizes_medium_url_Create + read: MediaDocAccessFields_sizes_medium_url_Read + update: MediaDocAccessFields_sizes_medium_url_Update + delete: MediaDocAccessFields_sizes_medium_url_Delete +} + +type MediaDocAccessFields_sizes_medium_url_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_url_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_url_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_url_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_width { + create: MediaDocAccessFields_sizes_medium_width_Create + read: MediaDocAccessFields_sizes_medium_width_Read + update: MediaDocAccessFields_sizes_medium_width_Update + delete: MediaDocAccessFields_sizes_medium_width_Delete +} + +type MediaDocAccessFields_sizes_medium_width_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_width_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_width_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_width_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_height { + create: MediaDocAccessFields_sizes_medium_height_Create + read: MediaDocAccessFields_sizes_medium_height_Read + update: MediaDocAccessFields_sizes_medium_height_Update + delete: MediaDocAccessFields_sizes_medium_height_Delete +} + +type MediaDocAccessFields_sizes_medium_height_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_height_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_height_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_height_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_mimeType { + create: MediaDocAccessFields_sizes_medium_mimeType_Create + read: MediaDocAccessFields_sizes_medium_mimeType_Read + update: MediaDocAccessFields_sizes_medium_mimeType_Update + delete: MediaDocAccessFields_sizes_medium_mimeType_Delete +} + +type MediaDocAccessFields_sizes_medium_mimeType_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_mimeType_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_mimeType_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_mimeType_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filesize { + create: MediaDocAccessFields_sizes_medium_filesize_Create + read: MediaDocAccessFields_sizes_medium_filesize_Read + update: MediaDocAccessFields_sizes_medium_filesize_Update + delete: MediaDocAccessFields_sizes_medium_filesize_Delete +} + +type MediaDocAccessFields_sizes_medium_filesize_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filesize_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filesize_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filesize_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filename { + create: MediaDocAccessFields_sizes_medium_filename_Create + read: MediaDocAccessFields_sizes_medium_filename_Read + update: MediaDocAccessFields_sizes_medium_filename_Update + delete: MediaDocAccessFields_sizes_medium_filename_Delete +} + +type MediaDocAccessFields_sizes_medium_filename_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filename_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filename_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_medium_filename_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large { + create: MediaDocAccessFields_sizes_large_Create + read: MediaDocAccessFields_sizes_large_Read + update: MediaDocAccessFields_sizes_large_Update + delete: MediaDocAccessFields_sizes_large_Delete + fields: MediaDocAccessFields_sizes_large_Fields +} + +type MediaDocAccessFields_sizes_large_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_Fields { + url: MediaDocAccessFields_sizes_large_url + width: MediaDocAccessFields_sizes_large_width + height: MediaDocAccessFields_sizes_large_height + mimeType: MediaDocAccessFields_sizes_large_mimeType + filesize: MediaDocAccessFields_sizes_large_filesize + filename: MediaDocAccessFields_sizes_large_filename +} + +type MediaDocAccessFields_sizes_large_url { + create: MediaDocAccessFields_sizes_large_url_Create + read: MediaDocAccessFields_sizes_large_url_Read + update: MediaDocAccessFields_sizes_large_url_Update + delete: MediaDocAccessFields_sizes_large_url_Delete +} + +type MediaDocAccessFields_sizes_large_url_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_url_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_url_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_url_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_width { + create: MediaDocAccessFields_sizes_large_width_Create + read: MediaDocAccessFields_sizes_large_width_Read + update: MediaDocAccessFields_sizes_large_width_Update + delete: MediaDocAccessFields_sizes_large_width_Delete +} + +type MediaDocAccessFields_sizes_large_width_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_width_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_width_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_width_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_height { + create: MediaDocAccessFields_sizes_large_height_Create + read: MediaDocAccessFields_sizes_large_height_Read + update: MediaDocAccessFields_sizes_large_height_Update + delete: MediaDocAccessFields_sizes_large_height_Delete +} + +type MediaDocAccessFields_sizes_large_height_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_height_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_height_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_height_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_mimeType { + create: MediaDocAccessFields_sizes_large_mimeType_Create + read: MediaDocAccessFields_sizes_large_mimeType_Read + update: MediaDocAccessFields_sizes_large_mimeType_Update + delete: MediaDocAccessFields_sizes_large_mimeType_Delete +} + +type MediaDocAccessFields_sizes_large_mimeType_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_mimeType_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_mimeType_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_mimeType_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filesize { + create: MediaDocAccessFields_sizes_large_filesize_Create + read: MediaDocAccessFields_sizes_large_filesize_Read + update: MediaDocAccessFields_sizes_large_filesize_Update + delete: MediaDocAccessFields_sizes_large_filesize_Delete +} + +type MediaDocAccessFields_sizes_large_filesize_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filesize_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filesize_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filesize_Delete { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filename { + create: MediaDocAccessFields_sizes_large_filename_Create + read: MediaDocAccessFields_sizes_large_filename_Read + update: MediaDocAccessFields_sizes_large_filename_Update + delete: MediaDocAccessFields_sizes_large_filename_Delete +} + +type MediaDocAccessFields_sizes_large_filename_Create { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filename_Read { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filename_Update { + permission: Boolean! +} + +type MediaDocAccessFields_sizes_large_filename_Delete { + permission: Boolean! +} + +type MediaCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type MediaReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type MediaUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type MediaDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type User { + id: String! + updatedAt: DateTime + createdAt: DateTime + email: EmailAddress! + resetPasswordToken: String + resetPasswordExpiration: DateTime + salt: String + hash: String + loginAttempts: Float + lockUntil: DateTime +} + +""" +A field whose value conforms to the standard internet email address format as specified in HTML Spec: https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address. +""" +scalar EmailAddress @specifiedBy(url: "https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address") + +type Users { + docs: [User!]! + hasNextPage: Boolean! + hasPrevPage: Boolean! + limit: Int! + nextPage: Int! + offset: Int + page: Int! + pagingCounter: Int! + prevPage: Int! + totalDocs: Int! + totalPages: Int! +} + +input User_where { + updatedAt: User_updatedAt_operator + createdAt: User_createdAt_operator + email: User_email_operator + id: User_id_operator + AND: [User_where_and] + OR: [User_where_or] +} + +input User_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input User_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input User_email_operator { + equals: EmailAddress + not_equals: EmailAddress + like: EmailAddress + contains: EmailAddress + in: [EmailAddress] + not_in: [EmailAddress] + all: [EmailAddress] +} + +input User_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input User_where_and { + updatedAt: User_updatedAt_operator + createdAt: User_createdAt_operator + email: User_email_operator + id: User_id_operator + AND: [User_where_and] + OR: [User_where_or] +} + +input User_where_or { + updatedAt: User_updatedAt_operator + createdAt: User_createdAt_operator + email: User_email_operator + id: User_id_operator + AND: [User_where_and] + OR: [User_where_or] +} + +type countUsers { + totalDocs: Int +} + +type usersDocAccess { + fields: UsersDocAccessFields + create: UsersCreateDocAccess + read: UsersReadDocAccess + update: UsersUpdateDocAccess + delete: UsersDeleteDocAccess + unlock: UsersUnlockDocAccess +} + +type UsersDocAccessFields { + updatedAt: UsersDocAccessFields_updatedAt + createdAt: UsersDocAccessFields_createdAt + email: UsersDocAccessFields_email +} + +type UsersDocAccessFields_updatedAt { + create: UsersDocAccessFields_updatedAt_Create + read: UsersDocAccessFields_updatedAt_Read + update: UsersDocAccessFields_updatedAt_Update + delete: UsersDocAccessFields_updatedAt_Delete +} + +type UsersDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type UsersDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type UsersDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type UsersDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt { + create: UsersDocAccessFields_createdAt_Create + read: UsersDocAccessFields_createdAt_Read + update: UsersDocAccessFields_createdAt_Update + delete: UsersDocAccessFields_createdAt_Delete +} + +type UsersDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type UsersDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type UsersDocAccessFields_email { + create: UsersDocAccessFields_email_Create + read: UsersDocAccessFields_email_Read + update: UsersDocAccessFields_email_Update + delete: UsersDocAccessFields_email_Delete +} + +type UsersDocAccessFields_email_Create { + permission: Boolean! +} + +type UsersDocAccessFields_email_Read { + permission: Boolean! +} + +type UsersDocAccessFields_email_Update { + permission: Boolean! +} + +type UsersDocAccessFields_email_Delete { + permission: Boolean! +} + +type UsersCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUnlockDocAccess { + permission: Boolean! + where: JSONObject +} + +type usersMe { + collection: String + exp: Int + strategy: String + token: String + user: User +} + +type PayloadLockedDocument { + id: String! + document: PayloadLockedDocument_Document_Relationship + globalSlug: String + user: PayloadLockedDocument_User_Relationship! + updatedAt: DateTime + createdAt: DateTime +} + +type PayloadLockedDocument_Document_Relationship { + relationTo: PayloadLockedDocument_Document_RelationTo + value: PayloadLockedDocument_Document +} + +enum PayloadLockedDocument_Document_RelationTo { + posts + media + users +} + +union PayloadLockedDocument_Document = Post | Media | User + +type PayloadLockedDocument_User_Relationship { + relationTo: PayloadLockedDocument_User_RelationTo + value: PayloadLockedDocument_User +} + +enum PayloadLockedDocument_User_RelationTo { + users +} + +union PayloadLockedDocument_User = User + +type PayloadLockedDocuments { + docs: [PayloadLockedDocument!]! + hasNextPage: Boolean! + hasPrevPage: Boolean! + limit: Int! + nextPage: Int! + offset: Int + page: Int! + pagingCounter: Int! + prevPage: Int! + totalDocs: Int! + totalPages: Int! +} + +input PayloadLockedDocument_where { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +input PayloadLockedDocument_document_Relation { + relationTo: PayloadLockedDocument_document_Relation_RelationTo + value: JSON +} + +enum PayloadLockedDocument_document_Relation_RelationTo { + posts + media + users +} + +input PayloadLockedDocument_globalSlug_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadLockedDocument_user_Relation { + relationTo: PayloadLockedDocument_user_Relation_RelationTo + value: JSON +} + +enum PayloadLockedDocument_user_Relation_RelationTo { + users +} + +input PayloadLockedDocument_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadLockedDocument_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadLockedDocument_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadLockedDocument_where_and { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +input PayloadLockedDocument_where_or { + document: PayloadLockedDocument_document_Relation + globalSlug: PayloadLockedDocument_globalSlug_operator + user: PayloadLockedDocument_user_Relation + updatedAt: PayloadLockedDocument_updatedAt_operator + createdAt: PayloadLockedDocument_createdAt_operator + id: PayloadLockedDocument_id_operator + AND: [PayloadLockedDocument_where_and] + OR: [PayloadLockedDocument_where_or] +} + +type countPayloadLockedDocuments { + totalDocs: Int +} + +type payload_locked_documentsDocAccess { + fields: PayloadLockedDocumentsDocAccessFields + create: PayloadLockedDocumentsCreateDocAccess + read: PayloadLockedDocumentsReadDocAccess + update: PayloadLockedDocumentsUpdateDocAccess + delete: PayloadLockedDocumentsDeleteDocAccess +} + +type PayloadLockedDocumentsDocAccessFields { + document: PayloadLockedDocumentsDocAccessFields_document + globalSlug: PayloadLockedDocumentsDocAccessFields_globalSlug + user: PayloadLockedDocumentsDocAccessFields_user + updatedAt: PayloadLockedDocumentsDocAccessFields_updatedAt + createdAt: PayloadLockedDocumentsDocAccessFields_createdAt +} + +type PayloadLockedDocumentsDocAccessFields_document { + create: PayloadLockedDocumentsDocAccessFields_document_Create + read: PayloadLockedDocumentsDocAccessFields_document_Read + update: PayloadLockedDocumentsDocAccessFields_document_Update + delete: PayloadLockedDocumentsDocAccessFields_document_Delete +} + +type PayloadLockedDocumentsDocAccessFields_document_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_document_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug { + create: PayloadLockedDocumentsDocAccessFields_globalSlug_Create + read: PayloadLockedDocumentsDocAccessFields_globalSlug_Read + update: PayloadLockedDocumentsDocAccessFields_globalSlug_Update + delete: PayloadLockedDocumentsDocAccessFields_globalSlug_Delete +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_globalSlug_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user { + create: PayloadLockedDocumentsDocAccessFields_user_Create + read: PayloadLockedDocumentsDocAccessFields_user_Read + update: PayloadLockedDocumentsDocAccessFields_user_Update + delete: PayloadLockedDocumentsDocAccessFields_user_Delete +} + +type PayloadLockedDocumentsDocAccessFields_user_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_user_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt { + create: PayloadLockedDocumentsDocAccessFields_updatedAt_Create + read: PayloadLockedDocumentsDocAccessFields_updatedAt_Read + update: PayloadLockedDocumentsDocAccessFields_updatedAt_Update + delete: PayloadLockedDocumentsDocAccessFields_updatedAt_Delete +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt { + create: PayloadLockedDocumentsDocAccessFields_createdAt_Create + read: PayloadLockedDocumentsDocAccessFields_createdAt_Read + update: PayloadLockedDocumentsDocAccessFields_createdAt_Update + delete: PayloadLockedDocumentsDocAccessFields_createdAt_Delete +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreference { + id: String! + user: PayloadPreference_User_Relationship! + key: String + value: JSON + updatedAt: DateTime + createdAt: DateTime +} + +type PayloadPreference_User_Relationship { + relationTo: PayloadPreference_User_RelationTo + value: PayloadPreference_User +} + +enum PayloadPreference_User_RelationTo { + users +} + +union PayloadPreference_User = User + +type PayloadPreferences { + docs: [PayloadPreference!]! + hasNextPage: Boolean! + hasPrevPage: Boolean! + limit: Int! + nextPage: Int! + offset: Int + page: Int! + pagingCounter: Int! + prevPage: Int! + totalDocs: Int! + totalPages: Int! +} + +input PayloadPreference_where { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator + AND: [PayloadPreference_where_and] + OR: [PayloadPreference_where_or] +} + +input PayloadPreference_user_Relation { + relationTo: PayloadPreference_user_Relation_RelationTo + value: JSON +} + +enum PayloadPreference_user_Relation_RelationTo { + users +} + +input PayloadPreference_key_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadPreference_value_operator { + equals: JSON + not_equals: JSON + like: JSON + contains: JSON + within: JSON + intersects: JSON + exists: Boolean +} + +input PayloadPreference_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadPreference_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadPreference_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadPreference_where_and { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator + AND: [PayloadPreference_where_and] + OR: [PayloadPreference_where_or] +} + +input PayloadPreference_where_or { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator + AND: [PayloadPreference_where_and] + OR: [PayloadPreference_where_or] +} + +type countPayloadPreferences { + totalDocs: Int +} + +type payload_preferencesDocAccess { + fields: PayloadPreferencesDocAccessFields + create: PayloadPreferencesCreateDocAccess + read: PayloadPreferencesReadDocAccess + update: PayloadPreferencesUpdateDocAccess + delete: PayloadPreferencesDeleteDocAccess +} + +type PayloadPreferencesDocAccessFields { + user: PayloadPreferencesDocAccessFields_user + key: PayloadPreferencesDocAccessFields_key + value: PayloadPreferencesDocAccessFields_value + updatedAt: PayloadPreferencesDocAccessFields_updatedAt + createdAt: PayloadPreferencesDocAccessFields_createdAt +} + +type PayloadPreferencesDocAccessFields_user { + create: PayloadPreferencesDocAccessFields_user_Create + read: PayloadPreferencesDocAccessFields_user_Read + update: PayloadPreferencesDocAccessFields_user_Update + delete: PayloadPreferencesDocAccessFields_user_Delete +} + +type PayloadPreferencesDocAccessFields_user_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key { + create: PayloadPreferencesDocAccessFields_key_Create + read: PayloadPreferencesDocAccessFields_key_Read + update: PayloadPreferencesDocAccessFields_key_Update + delete: PayloadPreferencesDocAccessFields_key_Delete +} + +type PayloadPreferencesDocAccessFields_key_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value { + create: PayloadPreferencesDocAccessFields_value_Create + read: PayloadPreferencesDocAccessFields_value_Read + update: PayloadPreferencesDocAccessFields_value_Update + delete: PayloadPreferencesDocAccessFields_value_Delete +} + +type PayloadPreferencesDocAccessFields_value_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt { + create: PayloadPreferencesDocAccessFields_updatedAt_Create + read: PayloadPreferencesDocAccessFields_updatedAt_Read + update: PayloadPreferencesDocAccessFields_updatedAt_Update + delete: PayloadPreferencesDocAccessFields_updatedAt_Delete +} + +type PayloadPreferencesDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt { + create: PayloadPreferencesDocAccessFields_createdAt_Create + read: PayloadPreferencesDocAccessFields_createdAt_Read + update: PayloadPreferencesDocAccessFields_createdAt_Update + delete: PayloadPreferencesDocAccessFields_createdAt_Delete +} + +type PayloadPreferencesDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + +type Menu { + globalText: String + updatedAt: DateTime + createdAt: DateTime +} + +type menuDocAccess { + fields: MenuDocAccessFields + read: MenuReadDocAccess + update: MenuUpdateDocAccess +} + +type MenuDocAccessFields { + globalText: MenuDocAccessFields_globalText + updatedAt: MenuDocAccessFields_updatedAt + createdAt: MenuDocAccessFields_createdAt +} + +type MenuDocAccessFields_globalText { + create: MenuDocAccessFields_globalText_Create + read: MenuDocAccessFields_globalText_Read + update: MenuDocAccessFields_globalText_Update + delete: MenuDocAccessFields_globalText_Delete +} + +type MenuDocAccessFields_globalText_Create { + permission: Boolean! +} + +type MenuDocAccessFields_globalText_Read { + permission: Boolean! +} + +type MenuDocAccessFields_globalText_Update { + permission: Boolean! +} + +type MenuDocAccessFields_globalText_Delete { + permission: Boolean! +} + +type MenuDocAccessFields_updatedAt { + create: MenuDocAccessFields_updatedAt_Create + read: MenuDocAccessFields_updatedAt_Read + update: MenuDocAccessFields_updatedAt_Update + delete: MenuDocAccessFields_updatedAt_Delete +} + +type MenuDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type MenuDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type MenuDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type MenuDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type MenuDocAccessFields_createdAt { + create: MenuDocAccessFields_createdAt_Create + read: MenuDocAccessFields_createdAt_Read + update: MenuDocAccessFields_createdAt_Update + delete: MenuDocAccessFields_createdAt_Delete +} + +type MenuDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type MenuDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type MenuDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type MenuDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type MenuReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type MenuUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type Access { + canAccessAdmin: Boolean! + posts: postsAccess + media: mediaAccess + users: usersAccess + payload_locked_documents: payload_locked_documentsAccess + payload_preferences: payload_preferencesAccess + menu: menuAccess +} + +type postsAccess { + fields: PostsFields + create: PostsCreateAccess + read: PostsReadAccess + update: PostsUpdateAccess + delete: PostsDeleteAccess +} + +type PostsFields { + title: PostsFields_title + content: PostsFields_content + updatedAt: PostsFields_updatedAt + createdAt: PostsFields_createdAt +} + +type PostsFields_title { + create: PostsFields_title_Create + read: PostsFields_title_Read + update: PostsFields_title_Update + delete: PostsFields_title_Delete +} + +type PostsFields_title_Create { + permission: Boolean! +} + +type PostsFields_title_Read { + permission: Boolean! +} + +type PostsFields_title_Update { + permission: Boolean! +} + +type PostsFields_title_Delete { + permission: Boolean! +} + +type PostsFields_content { + create: PostsFields_content_Create + read: PostsFields_content_Read + update: PostsFields_content_Update + delete: PostsFields_content_Delete +} + +type PostsFields_content_Create { + permission: Boolean! +} + +type PostsFields_content_Read { + permission: Boolean! +} + +type PostsFields_content_Update { + permission: Boolean! +} + +type PostsFields_content_Delete { + permission: Boolean! +} + +type PostsFields_updatedAt { + create: PostsFields_updatedAt_Create + read: PostsFields_updatedAt_Read + update: PostsFields_updatedAt_Update + delete: PostsFields_updatedAt_Delete +} + +type PostsFields_updatedAt_Create { + permission: Boolean! +} + +type PostsFields_updatedAt_Read { + permission: Boolean! +} + +type PostsFields_updatedAt_Update { + permission: Boolean! +} + +type PostsFields_updatedAt_Delete { + permission: Boolean! +} + +type PostsFields_createdAt { + create: PostsFields_createdAt_Create + read: PostsFields_createdAt_Read + update: PostsFields_createdAt_Update + delete: PostsFields_createdAt_Delete +} + +type PostsFields_createdAt_Create { + permission: Boolean! +} + +type PostsFields_createdAt_Read { + permission: Boolean! +} + +type PostsFields_createdAt_Update { + permission: Boolean! +} + +type PostsFields_createdAt_Delete { + permission: Boolean! +} + +type PostsCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PostsReadAccess { + permission: Boolean! + where: JSONObject +} + +type PostsUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PostsDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type mediaAccess { + fields: MediaFields + create: MediaCreateAccess + read: MediaReadAccess + update: MediaUpdateAccess + delete: MediaDeleteAccess +} + +type MediaFields { + updatedAt: MediaFields_updatedAt + createdAt: MediaFields_createdAt + url: MediaFields_url + thumbnailURL: MediaFields_thumbnailURL + filename: MediaFields_filename + mimeType: MediaFields_mimeType + filesize: MediaFields_filesize + width: MediaFields_width + height: MediaFields_height + focalX: MediaFields_focalX + focalY: MediaFields_focalY + sizes: MediaFields_sizes +} + +type MediaFields_updatedAt { + create: MediaFields_updatedAt_Create + read: MediaFields_updatedAt_Read + update: MediaFields_updatedAt_Update + delete: MediaFields_updatedAt_Delete +} + +type MediaFields_updatedAt_Create { + permission: Boolean! +} + +type MediaFields_updatedAt_Read { + permission: Boolean! +} + +type MediaFields_updatedAt_Update { + permission: Boolean! +} + +type MediaFields_updatedAt_Delete { + permission: Boolean! +} + +type MediaFields_createdAt { + create: MediaFields_createdAt_Create + read: MediaFields_createdAt_Read + update: MediaFields_createdAt_Update + delete: MediaFields_createdAt_Delete +} + +type MediaFields_createdAt_Create { + permission: Boolean! +} + +type MediaFields_createdAt_Read { + permission: Boolean! +} + +type MediaFields_createdAt_Update { + permission: Boolean! +} + +type MediaFields_createdAt_Delete { + permission: Boolean! +} + +type MediaFields_url { + create: MediaFields_url_Create + read: MediaFields_url_Read + update: MediaFields_url_Update + delete: MediaFields_url_Delete +} + +type MediaFields_url_Create { + permission: Boolean! +} + +type MediaFields_url_Read { + permission: Boolean! +} + +type MediaFields_url_Update { + permission: Boolean! +} + +type MediaFields_url_Delete { + permission: Boolean! +} + +type MediaFields_thumbnailURL { + create: MediaFields_thumbnailURL_Create + read: MediaFields_thumbnailURL_Read + update: MediaFields_thumbnailURL_Update + delete: MediaFields_thumbnailURL_Delete +} + +type MediaFields_thumbnailURL_Create { + permission: Boolean! +} + +type MediaFields_thumbnailURL_Read { + permission: Boolean! +} + +type MediaFields_thumbnailURL_Update { + permission: Boolean! +} + +type MediaFields_thumbnailURL_Delete { + permission: Boolean! +} + +type MediaFields_filename { + create: MediaFields_filename_Create + read: MediaFields_filename_Read + update: MediaFields_filename_Update + delete: MediaFields_filename_Delete +} + +type MediaFields_filename_Create { + permission: Boolean! +} + +type MediaFields_filename_Read { + permission: Boolean! +} + +type MediaFields_filename_Update { + permission: Boolean! +} + +type MediaFields_filename_Delete { + permission: Boolean! +} + +type MediaFields_mimeType { + create: MediaFields_mimeType_Create + read: MediaFields_mimeType_Read + update: MediaFields_mimeType_Update + delete: MediaFields_mimeType_Delete +} + +type MediaFields_mimeType_Create { + permission: Boolean! +} + +type MediaFields_mimeType_Read { + permission: Boolean! +} + +type MediaFields_mimeType_Update { + permission: Boolean! +} + +type MediaFields_mimeType_Delete { + permission: Boolean! +} + +type MediaFields_filesize { + create: MediaFields_filesize_Create + read: MediaFields_filesize_Read + update: MediaFields_filesize_Update + delete: MediaFields_filesize_Delete +} + +type MediaFields_filesize_Create { + permission: Boolean! +} + +type MediaFields_filesize_Read { + permission: Boolean! +} + +type MediaFields_filesize_Update { + permission: Boolean! +} + +type MediaFields_filesize_Delete { + permission: Boolean! +} + +type MediaFields_width { + create: MediaFields_width_Create + read: MediaFields_width_Read + update: MediaFields_width_Update + delete: MediaFields_width_Delete +} + +type MediaFields_width_Create { + permission: Boolean! +} + +type MediaFields_width_Read { + permission: Boolean! +} + +type MediaFields_width_Update { + permission: Boolean! +} + +type MediaFields_width_Delete { + permission: Boolean! +} + +type MediaFields_height { + create: MediaFields_height_Create + read: MediaFields_height_Read + update: MediaFields_height_Update + delete: MediaFields_height_Delete +} + +type MediaFields_height_Create { + permission: Boolean! +} + +type MediaFields_height_Read { + permission: Boolean! +} + +type MediaFields_height_Update { + permission: Boolean! +} + +type MediaFields_height_Delete { + permission: Boolean! +} + +type MediaFields_focalX { + create: MediaFields_focalX_Create + read: MediaFields_focalX_Read + update: MediaFields_focalX_Update + delete: MediaFields_focalX_Delete +} + +type MediaFields_focalX_Create { + permission: Boolean! +} + +type MediaFields_focalX_Read { + permission: Boolean! +} + +type MediaFields_focalX_Update { + permission: Boolean! +} + +type MediaFields_focalX_Delete { + permission: Boolean! +} + +type MediaFields_focalY { + create: MediaFields_focalY_Create + read: MediaFields_focalY_Read + update: MediaFields_focalY_Update + delete: MediaFields_focalY_Delete +} + +type MediaFields_focalY_Create { + permission: Boolean! +} + +type MediaFields_focalY_Read { + permission: Boolean! +} + +type MediaFields_focalY_Update { + permission: Boolean! +} + +type MediaFields_focalY_Delete { + permission: Boolean! +} + +type MediaFields_sizes { + create: MediaFields_sizes_Create + read: MediaFields_sizes_Read + update: MediaFields_sizes_Update + delete: MediaFields_sizes_Delete + fields: MediaFields_sizes_Fields +} + +type MediaFields_sizes_Create { + permission: Boolean! +} + +type MediaFields_sizes_Read { + permission: Boolean! +} + +type MediaFields_sizes_Update { + permission: Boolean! +} + +type MediaFields_sizes_Delete { + permission: Boolean! +} + +type MediaFields_sizes_Fields { + thumbnail: MediaFields_sizes_thumbnail + medium: MediaFields_sizes_medium + large: MediaFields_sizes_large +} + +type MediaFields_sizes_thumbnail { + create: MediaFields_sizes_thumbnail_Create + read: MediaFields_sizes_thumbnail_Read + update: MediaFields_sizes_thumbnail_Update + delete: MediaFields_sizes_thumbnail_Delete + fields: MediaFields_sizes_thumbnail_Fields +} + +type MediaFields_sizes_thumbnail_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_Fields { + url: MediaFields_sizes_thumbnail_url + width: MediaFields_sizes_thumbnail_width + height: MediaFields_sizes_thumbnail_height + mimeType: MediaFields_sizes_thumbnail_mimeType + filesize: MediaFields_sizes_thumbnail_filesize + filename: MediaFields_sizes_thumbnail_filename +} + +type MediaFields_sizes_thumbnail_url { + create: MediaFields_sizes_thumbnail_url_Create + read: MediaFields_sizes_thumbnail_url_Read + update: MediaFields_sizes_thumbnail_url_Update + delete: MediaFields_sizes_thumbnail_url_Delete +} + +type MediaFields_sizes_thumbnail_url_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_url_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_url_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_url_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_width { + create: MediaFields_sizes_thumbnail_width_Create + read: MediaFields_sizes_thumbnail_width_Read + update: MediaFields_sizes_thumbnail_width_Update + delete: MediaFields_sizes_thumbnail_width_Delete +} + +type MediaFields_sizes_thumbnail_width_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_width_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_width_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_width_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_height { + create: MediaFields_sizes_thumbnail_height_Create + read: MediaFields_sizes_thumbnail_height_Read + update: MediaFields_sizes_thumbnail_height_Update + delete: MediaFields_sizes_thumbnail_height_Delete +} + +type MediaFields_sizes_thumbnail_height_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_height_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_height_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_height_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_mimeType { + create: MediaFields_sizes_thumbnail_mimeType_Create + read: MediaFields_sizes_thumbnail_mimeType_Read + update: MediaFields_sizes_thumbnail_mimeType_Update + delete: MediaFields_sizes_thumbnail_mimeType_Delete +} + +type MediaFields_sizes_thumbnail_mimeType_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_mimeType_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_mimeType_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_mimeType_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filesize { + create: MediaFields_sizes_thumbnail_filesize_Create + read: MediaFields_sizes_thumbnail_filesize_Read + update: MediaFields_sizes_thumbnail_filesize_Update + delete: MediaFields_sizes_thumbnail_filesize_Delete +} + +type MediaFields_sizes_thumbnail_filesize_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filesize_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filesize_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filesize_Delete { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filename { + create: MediaFields_sizes_thumbnail_filename_Create + read: MediaFields_sizes_thumbnail_filename_Read + update: MediaFields_sizes_thumbnail_filename_Update + delete: MediaFields_sizes_thumbnail_filename_Delete +} + +type MediaFields_sizes_thumbnail_filename_Create { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filename_Read { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filename_Update { + permission: Boolean! +} + +type MediaFields_sizes_thumbnail_filename_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium { + create: MediaFields_sizes_medium_Create + read: MediaFields_sizes_medium_Read + update: MediaFields_sizes_medium_Update + delete: MediaFields_sizes_medium_Delete + fields: MediaFields_sizes_medium_Fields +} + +type MediaFields_sizes_medium_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_Fields { + url: MediaFields_sizes_medium_url + width: MediaFields_sizes_medium_width + height: MediaFields_sizes_medium_height + mimeType: MediaFields_sizes_medium_mimeType + filesize: MediaFields_sizes_medium_filesize + filename: MediaFields_sizes_medium_filename +} + +type MediaFields_sizes_medium_url { + create: MediaFields_sizes_medium_url_Create + read: MediaFields_sizes_medium_url_Read + update: MediaFields_sizes_medium_url_Update + delete: MediaFields_sizes_medium_url_Delete +} + +type MediaFields_sizes_medium_url_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_url_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_url_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_url_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_width { + create: MediaFields_sizes_medium_width_Create + read: MediaFields_sizes_medium_width_Read + update: MediaFields_sizes_medium_width_Update + delete: MediaFields_sizes_medium_width_Delete +} + +type MediaFields_sizes_medium_width_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_width_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_width_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_width_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_height { + create: MediaFields_sizes_medium_height_Create + read: MediaFields_sizes_medium_height_Read + update: MediaFields_sizes_medium_height_Update + delete: MediaFields_sizes_medium_height_Delete +} + +type MediaFields_sizes_medium_height_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_height_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_height_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_height_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_mimeType { + create: MediaFields_sizes_medium_mimeType_Create + read: MediaFields_sizes_medium_mimeType_Read + update: MediaFields_sizes_medium_mimeType_Update + delete: MediaFields_sizes_medium_mimeType_Delete +} + +type MediaFields_sizes_medium_mimeType_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_mimeType_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_mimeType_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_mimeType_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_filesize { + create: MediaFields_sizes_medium_filesize_Create + read: MediaFields_sizes_medium_filesize_Read + update: MediaFields_sizes_medium_filesize_Update + delete: MediaFields_sizes_medium_filesize_Delete +} + +type MediaFields_sizes_medium_filesize_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_filesize_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_filesize_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_filesize_Delete { + permission: Boolean! +} + +type MediaFields_sizes_medium_filename { + create: MediaFields_sizes_medium_filename_Create + read: MediaFields_sizes_medium_filename_Read + update: MediaFields_sizes_medium_filename_Update + delete: MediaFields_sizes_medium_filename_Delete +} + +type MediaFields_sizes_medium_filename_Create { + permission: Boolean! +} + +type MediaFields_sizes_medium_filename_Read { + permission: Boolean! +} + +type MediaFields_sizes_medium_filename_Update { + permission: Boolean! +} + +type MediaFields_sizes_medium_filename_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large { + create: MediaFields_sizes_large_Create + read: MediaFields_sizes_large_Read + update: MediaFields_sizes_large_Update + delete: MediaFields_sizes_large_Delete + fields: MediaFields_sizes_large_Fields +} + +type MediaFields_sizes_large_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_Fields { + url: MediaFields_sizes_large_url + width: MediaFields_sizes_large_width + height: MediaFields_sizes_large_height + mimeType: MediaFields_sizes_large_mimeType + filesize: MediaFields_sizes_large_filesize + filename: MediaFields_sizes_large_filename +} + +type MediaFields_sizes_large_url { + create: MediaFields_sizes_large_url_Create + read: MediaFields_sizes_large_url_Read + update: MediaFields_sizes_large_url_Update + delete: MediaFields_sizes_large_url_Delete +} + +type MediaFields_sizes_large_url_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_url_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_url_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_url_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_width { + create: MediaFields_sizes_large_width_Create + read: MediaFields_sizes_large_width_Read + update: MediaFields_sizes_large_width_Update + delete: MediaFields_sizes_large_width_Delete +} + +type MediaFields_sizes_large_width_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_width_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_width_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_width_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_height { + create: MediaFields_sizes_large_height_Create + read: MediaFields_sizes_large_height_Read + update: MediaFields_sizes_large_height_Update + delete: MediaFields_sizes_large_height_Delete +} + +type MediaFields_sizes_large_height_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_height_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_height_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_height_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_mimeType { + create: MediaFields_sizes_large_mimeType_Create + read: MediaFields_sizes_large_mimeType_Read + update: MediaFields_sizes_large_mimeType_Update + delete: MediaFields_sizes_large_mimeType_Delete +} + +type MediaFields_sizes_large_mimeType_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_mimeType_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_mimeType_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_mimeType_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_filesize { + create: MediaFields_sizes_large_filesize_Create + read: MediaFields_sizes_large_filesize_Read + update: MediaFields_sizes_large_filesize_Update + delete: MediaFields_sizes_large_filesize_Delete +} + +type MediaFields_sizes_large_filesize_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_filesize_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_filesize_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_filesize_Delete { + permission: Boolean! +} + +type MediaFields_sizes_large_filename { + create: MediaFields_sizes_large_filename_Create + read: MediaFields_sizes_large_filename_Read + update: MediaFields_sizes_large_filename_Update + delete: MediaFields_sizes_large_filename_Delete +} + +type MediaFields_sizes_large_filename_Create { + permission: Boolean! +} + +type MediaFields_sizes_large_filename_Read { + permission: Boolean! +} + +type MediaFields_sizes_large_filename_Update { + permission: Boolean! +} + +type MediaFields_sizes_large_filename_Delete { + permission: Boolean! +} + +type MediaCreateAccess { + permission: Boolean! + where: JSONObject +} + +type MediaReadAccess { + permission: Boolean! + where: JSONObject +} + +type MediaUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type MediaDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type usersAccess { + fields: UsersFields + create: UsersCreateAccess + read: UsersReadAccess + update: UsersUpdateAccess + delete: UsersDeleteAccess + unlock: UsersUnlockAccess +} + +type UsersFields { + updatedAt: UsersFields_updatedAt + createdAt: UsersFields_createdAt + email: UsersFields_email +} + +type UsersFields_updatedAt { + create: UsersFields_updatedAt_Create + read: UsersFields_updatedAt_Read + update: UsersFields_updatedAt_Update + delete: UsersFields_updatedAt_Delete +} + +type UsersFields_updatedAt_Create { + permission: Boolean! +} + +type UsersFields_updatedAt_Read { + permission: Boolean! +} + +type UsersFields_updatedAt_Update { + permission: Boolean! +} + +type UsersFields_updatedAt_Delete { + permission: Boolean! +} + +type UsersFields_createdAt { + create: UsersFields_createdAt_Create + read: UsersFields_createdAt_Read + update: UsersFields_createdAt_Update + delete: UsersFields_createdAt_Delete +} + +type UsersFields_createdAt_Create { + permission: Boolean! +} + +type UsersFields_createdAt_Read { + permission: Boolean! +} + +type UsersFields_createdAt_Update { + permission: Boolean! +} + +type UsersFields_createdAt_Delete { + permission: Boolean! +} + +type UsersFields_email { + create: UsersFields_email_Create + read: UsersFields_email_Read + update: UsersFields_email_Update + delete: UsersFields_email_Delete +} + +type UsersFields_email_Create { + permission: Boolean! +} + +type UsersFields_email_Read { + permission: Boolean! +} + +type UsersFields_email_Update { + permission: Boolean! +} + +type UsersFields_email_Delete { + permission: Boolean! +} + +type UsersCreateAccess { + permission: Boolean! + where: JSONObject +} + +type UsersReadAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type UsersDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type UsersUnlockAccess { + permission: Boolean! + where: JSONObject +} + +type payload_locked_documentsAccess { + fields: PayloadLockedDocumentsFields + create: PayloadLockedDocumentsCreateAccess + read: PayloadLockedDocumentsReadAccess + update: PayloadLockedDocumentsUpdateAccess + delete: PayloadLockedDocumentsDeleteAccess +} + +type PayloadLockedDocumentsFields { + document: PayloadLockedDocumentsFields_document + globalSlug: PayloadLockedDocumentsFields_globalSlug + user: PayloadLockedDocumentsFields_user + updatedAt: PayloadLockedDocumentsFields_updatedAt + createdAt: PayloadLockedDocumentsFields_createdAt +} + +type PayloadLockedDocumentsFields_document { + create: PayloadLockedDocumentsFields_document_Create + read: PayloadLockedDocumentsFields_document_Read + update: PayloadLockedDocumentsFields_document_Update + delete: PayloadLockedDocumentsFields_document_Delete +} + +type PayloadLockedDocumentsFields_document_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_document_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug { + create: PayloadLockedDocumentsFields_globalSlug_Create + read: PayloadLockedDocumentsFields_globalSlug_Read + update: PayloadLockedDocumentsFields_globalSlug_Update + delete: PayloadLockedDocumentsFields_globalSlug_Delete +} + +type PayloadLockedDocumentsFields_globalSlug_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_globalSlug_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user { + create: PayloadLockedDocumentsFields_user_Create + read: PayloadLockedDocumentsFields_user_Read + update: PayloadLockedDocumentsFields_user_Update + delete: PayloadLockedDocumentsFields_user_Delete +} + +type PayloadLockedDocumentsFields_user_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_user_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt { + create: PayloadLockedDocumentsFields_updatedAt_Create + read: PayloadLockedDocumentsFields_updatedAt_Read + update: PayloadLockedDocumentsFields_updatedAt_Update + delete: PayloadLockedDocumentsFields_updatedAt_Delete +} + +type PayloadLockedDocumentsFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt { + create: PayloadLockedDocumentsFields_createdAt_Create + read: PayloadLockedDocumentsFields_createdAt_Read + update: PayloadLockedDocumentsFields_createdAt_Update + delete: PayloadLockedDocumentsFields_createdAt_Delete +} + +type PayloadLockedDocumentsFields_createdAt_Create { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Read { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Update { + permission: Boolean! +} + +type PayloadLockedDocumentsFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadLockedDocumentsCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsReadAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadLockedDocumentsDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type payload_preferencesAccess { + fields: PayloadPreferencesFields + create: PayloadPreferencesCreateAccess + read: PayloadPreferencesReadAccess + update: PayloadPreferencesUpdateAccess + delete: PayloadPreferencesDeleteAccess +} + +type PayloadPreferencesFields { + user: PayloadPreferencesFields_user + key: PayloadPreferencesFields_key + value: PayloadPreferencesFields_value + updatedAt: PayloadPreferencesFields_updatedAt + createdAt: PayloadPreferencesFields_createdAt +} + +type PayloadPreferencesFields_user { + create: PayloadPreferencesFields_user_Create + read: PayloadPreferencesFields_user_Read + update: PayloadPreferencesFields_user_Update + delete: PayloadPreferencesFields_user_Delete +} + +type PayloadPreferencesFields_user_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_key { + create: PayloadPreferencesFields_key_Create + read: PayloadPreferencesFields_key_Read + update: PayloadPreferencesFields_key_Update + delete: PayloadPreferencesFields_key_Delete +} + +type PayloadPreferencesFields_key_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_value { + create: PayloadPreferencesFields_value_Create + read: PayloadPreferencesFields_value_Read + update: PayloadPreferencesFields_value_Update + delete: PayloadPreferencesFields_value_Delete +} + +type PayloadPreferencesFields_value_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt { + create: PayloadPreferencesFields_updatedAt_Create + read: PayloadPreferencesFields_updatedAt_Read + update: PayloadPreferencesFields_updatedAt_Update + delete: PayloadPreferencesFields_updatedAt_Delete +} + +type PayloadPreferencesFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt { + create: PayloadPreferencesFields_createdAt_Create + read: PayloadPreferencesFields_createdAt_Read + update: PayloadPreferencesFields_createdAt_Update + delete: PayloadPreferencesFields_createdAt_Delete +} + +type PayloadPreferencesFields_createdAt_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesReadAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesDeleteAccess { + permission: Boolean! + where: JSONObject +} + +type menuAccess { + fields: MenuFields + read: MenuReadAccess + update: MenuUpdateAccess +} + +type MenuFields { + globalText: MenuFields_globalText + updatedAt: MenuFields_updatedAt + createdAt: MenuFields_createdAt +} + +type MenuFields_globalText { + create: MenuFields_globalText_Create + read: MenuFields_globalText_Read + update: MenuFields_globalText_Update + delete: MenuFields_globalText_Delete +} + +type MenuFields_globalText_Create { + permission: Boolean! +} + +type MenuFields_globalText_Read { + permission: Boolean! +} + +type MenuFields_globalText_Update { + permission: Boolean! +} + +type MenuFields_globalText_Delete { + permission: Boolean! +} + +type MenuFields_updatedAt { + create: MenuFields_updatedAt_Create + read: MenuFields_updatedAt_Read + update: MenuFields_updatedAt_Update + delete: MenuFields_updatedAt_Delete +} + +type MenuFields_updatedAt_Create { + permission: Boolean! +} + +type MenuFields_updatedAt_Read { + permission: Boolean! +} + +type MenuFields_updatedAt_Update { + permission: Boolean! +} + +type MenuFields_updatedAt_Delete { + permission: Boolean! +} + +type MenuFields_createdAt { + create: MenuFields_createdAt_Create + read: MenuFields_createdAt_Read + update: MenuFields_createdAt_Update + delete: MenuFields_createdAt_Delete +} + +type MenuFields_createdAt_Create { + permission: Boolean! +} + +type MenuFields_createdAt_Read { + permission: Boolean! +} + +type MenuFields_createdAt_Update { + permission: Boolean! +} + +type MenuFields_createdAt_Delete { + permission: Boolean! +} + +type MenuReadAccess { + permission: Boolean! + where: JSONObject +} + +type MenuUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type Mutation { + createPost(data: mutationPostInput!, draft: Boolean): Post + updatePost(id: String!, autosave: Boolean, data: mutationPostUpdateInput!, draft: Boolean): Post + deletePost(id: String!): Post + duplicatePost(id: String!, data: mutationPostInput!): Post + createMedia(data: mutationMediaInput!, draft: Boolean): Media + updateMedia(id: String!, autosave: Boolean, data: mutationMediaUpdateInput!, draft: Boolean): Media + deleteMedia(id: String!): Media + duplicateMedia(id: String!, data: mutationMediaInput!): Media + createUser(data: mutationUserInput!, draft: Boolean): User + updateUser(id: String!, autosave: Boolean, data: mutationUserUpdateInput!, draft: Boolean): User + deleteUser(id: String!): User + refreshTokenUser: usersRefreshedUser + logoutUser: String + unlockUser(email: String!): Boolean! + loginUser(email: String!, password: String): usersLoginResult + forgotPasswordUser(disableEmail: Boolean, expiration: Int, email: String!): Boolean! + resetPasswordUser(password: String, token: String): usersResetPassword + verifyEmailUser(token: String): Boolean + createPayloadLockedDocument(data: mutationPayloadLockedDocumentInput!, draft: Boolean): PayloadLockedDocument + updatePayloadLockedDocument(id: String!, autosave: Boolean, data: mutationPayloadLockedDocumentUpdateInput!, draft: Boolean): PayloadLockedDocument + deletePayloadLockedDocument(id: String!): PayloadLockedDocument + duplicatePayloadLockedDocument(id: String!, data: mutationPayloadLockedDocumentInput!): PayloadLockedDocument + createPayloadPreference(data: mutationPayloadPreferenceInput!, draft: Boolean): PayloadPreference + updatePayloadPreference(id: String!, autosave: Boolean, data: mutationPayloadPreferenceUpdateInput!, draft: Boolean): PayloadPreference + deletePayloadPreference(id: String!): PayloadPreference + duplicatePayloadPreference(id: String!, data: mutationPayloadPreferenceInput!): PayloadPreference + updateMenu(data: mutationMenuInput!, draft: Boolean): Menu +} + +input mutationPostInput { + title: String + content: JSON + updatedAt: String + createdAt: String +} + +input mutationPostUpdateInput { + title: String + content: JSON + updatedAt: String + createdAt: String +} + +input mutationMediaInput { + updatedAt: String + createdAt: String + url: String + thumbnailURL: String + filename: String + mimeType: String + filesize: Float + width: Float + height: Float + focalX: Float + focalY: Float + sizes: mutationMedia_SizesInput +} + +input mutationMedia_SizesInput { + thumbnail: mutationMedia_Sizes_ThumbnailInput + medium: mutationMedia_Sizes_MediumInput + large: mutationMedia_Sizes_LargeInput +} + +input mutationMedia_Sizes_ThumbnailInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationMedia_Sizes_MediumInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationMedia_Sizes_LargeInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationMediaUpdateInput { + updatedAt: String + createdAt: String + url: String + thumbnailURL: String + filename: String + mimeType: String + filesize: Float + width: Float + height: Float + focalX: Float + focalY: Float + sizes: mutationMediaUpdate_SizesInput +} + +input mutationMediaUpdate_SizesInput { + thumbnail: mutationMediaUpdate_Sizes_ThumbnailInput + medium: mutationMediaUpdate_Sizes_MediumInput + large: mutationMediaUpdate_Sizes_LargeInput +} + +input mutationMediaUpdate_Sizes_ThumbnailInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationMediaUpdate_Sizes_MediumInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationMediaUpdate_Sizes_LargeInput { + url: String + width: Float + height: Float + mimeType: String + filesize: Float + filename: String +} + +input mutationUserInput { + updatedAt: String + createdAt: String + email: String! + resetPasswordToken: String + resetPasswordExpiration: String + salt: String + hash: String + loginAttempts: Float + lockUntil: String + password: String! +} + +input mutationUserUpdateInput { + updatedAt: String + createdAt: String + email: String + resetPasswordToken: String + resetPasswordExpiration: String + salt: String + hash: String + loginAttempts: Float + lockUntil: String + password: String +} + +type usersRefreshedUser { + exp: Int + refreshedToken: String + strategy: String + user: usersJWT +} + +type usersJWT { + email: EmailAddress! + collection: String! +} + +type usersLoginResult { + exp: Int + token: String + user: User +} + +type usersResetPassword { + token: String + user: User +} + +input mutationPayloadLockedDocumentInput { + document: PayloadLockedDocument_DocumentRelationshipInput + globalSlug: String + user: PayloadLockedDocument_UserRelationshipInput + updatedAt: String + createdAt: String +} + +input PayloadLockedDocument_DocumentRelationshipInput { + relationTo: PayloadLockedDocument_DocumentRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocument_DocumentRelationshipInputRelationTo { + posts + media + users +} + +input PayloadLockedDocument_UserRelationshipInput { + relationTo: PayloadLockedDocument_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocument_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadLockedDocumentUpdateInput { + document: PayloadLockedDocumentUpdate_DocumentRelationshipInput + globalSlug: String + user: PayloadLockedDocumentUpdate_UserRelationshipInput + updatedAt: String + createdAt: String +} + +input PayloadLockedDocumentUpdate_DocumentRelationshipInput { + relationTo: PayloadLockedDocumentUpdate_DocumentRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocumentUpdate_DocumentRelationshipInputRelationTo { + posts + media + users +} + +input PayloadLockedDocumentUpdate_UserRelationshipInput { + relationTo: PayloadLockedDocumentUpdate_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadLockedDocumentUpdate_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadPreferenceInput { + user: PayloadPreference_UserRelationshipInput + key: String + value: JSON + updatedAt: String + createdAt: String +} + +input PayloadPreference_UserRelationshipInput { + relationTo: PayloadPreference_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadPreference_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadPreferenceUpdateInput { + user: PayloadPreferenceUpdate_UserRelationshipInput + key: String + value: JSON + updatedAt: String + createdAt: String +} + +input PayloadPreferenceUpdate_UserRelationshipInput { + relationTo: PayloadPreferenceUpdate_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadPreferenceUpdate_UserRelationshipInputRelationTo { + users +} + +input mutationMenuInput { + globalText: String + updatedAt: String + createdAt: String +} \ No newline at end of file diff --git a/test/server-url/tsconfig.eslint.json b/test/server-url/tsconfig.eslint.json new file mode 100644 index 00000000000..b34cc7afbb8 --- /dev/null +++ b/test/server-url/tsconfig.eslint.json @@ -0,0 +1,13 @@ +{ + // extend your base config to share compilerOptions, etc + //"extends": "./tsconfig.json", + "compilerOptions": { + // ensure that nobody can accidentally use this config for a build + "noEmit": true + }, + "include": [ + // whatever paths you intend to lint + "./**/*.ts", + "./**/*.tsx" + ] +} diff --git a/test/server-url/tsconfig.json b/test/server-url/tsconfig.json new file mode 100644 index 00000000000..3c43903cfdd --- /dev/null +++ b/test/server-url/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.json" +} diff --git a/test/server-url/types.d.ts b/test/server-url/types.d.ts new file mode 100644 index 00000000000..8d5bd7d65c3 --- /dev/null +++ b/test/server-url/types.d.ts @@ -0,0 +1,9 @@ +import type { RequestContext as OriginalRequestContext } from 'payload' + +declare module 'payload' { + // Create a new interface that merges your additional fields with the original one + export interface RequestContext extends OriginalRequestContext { + myObject?: string + // ... + } +} From c4fe1779adf2cf961c4318f2daad02d542c1958a Mon Sep 17 00:00:00 2001 From: Jake Date: Sun, 14 Dec 2025 09:56:10 -0500 Subject: [PATCH 10/67] fix(deps)!: enforce Next.js 15.4.10 (#14908) Address [CVE-2025-67779](https://www.cve.org/CVERecord?id=CVE-2025-67779). > The initial fix was incomplete and did not fully prevent denial-of-service attacks for all payload types, resulting in [CVE-2025-67779](https://www.cve.org/CVERecord?id=CVE-2025-67779). Everyone must upgrade to the latest patched versions listed in the [Patched versions table](https://vercel.com/kb/bulletin/security-bulletin-cve-2025-55184-and-cve-2025-55183#patched-versions). Source: https://vercel.com/kb/bulletin/security-bulletin-cve-2025-55184-and-cve-2025-55183#how-to-upgrade-and-protect-your-next.js-app Related: https://github.com/payloadcms/payload/pull/14898 and https://github.com/payloadcms/payload/pull/14815 --- examples/astro/payload/package.json | 2 +- examples/astro/payload/pnpm-lock.yaml | 38 ++++----- examples/astro/pnpm-lock.yaml | 84 ++++++++++--------- examples/auth/package.json | 2 +- examples/auth/pnpm-lock.yaml | 3 +- examples/custom-components/package.json | 2 +- examples/custom-components/pnpm-lock.yaml | 13 +-- examples/custom-server/package.json | 2 +- examples/custom-server/pnpm-lock.yaml | 38 ++++----- examples/draft-preview/package.json | 2 +- examples/draft-preview/pnpm-lock.yaml | 3 +- examples/email/package.json | 2 +- examples/email/pnpm-lock.yaml | 3 +- examples/form-builder/package.json | 2 +- examples/form-builder/pnpm-lock.yaml | 3 +- examples/live-preview/package.json | 2 +- examples/live-preview/pnpm-lock.yaml | 3 +- examples/localization/package.json | 2 +- examples/localization/pnpm-lock.yaml | 2 +- examples/multi-tenant/package.json | 2 +- examples/multi-tenant/pnpm-lock.yaml | 3 +- examples/remix/payload/package.json | 2 +- examples/remix/payload/pnpm-lock.yaml | 3 +- examples/tailwind-shadcn-ui/package.json | 2 +- examples/tailwind-shadcn-ui/pnpm-lock.yaml | 3 +- examples/whitelabel/package.json | 2 +- examples/whitelabel/pnpm-lock.yaml | 3 +- package.json | 2 +- packages/next/package.json | 2 +- packages/ui/package.json | 2 +- pnpm-lock.yaml | 80 +++++++++--------- templates/_template/package.json | 2 +- templates/blank/package.json | 2 +- templates/ecommerce/package.json | 2 +- templates/plugin/package.json | 2 +- templates/website/package.json | 2 +- templates/with-cloudflare-d1/package.json | 2 +- templates/with-postgres/package.json | 2 +- templates/with-vercel-mongodb/package.json | 2 +- templates/with-vercel-postgres/package.json | 2 +- templates/with-vercel-website/package.json | 2 +- test/package.json | 2 +- .../payload/reference/PLUGIN-DEVELOPMENT.md | 2 +- 43 files changed, 177 insertions(+), 161 deletions(-) diff --git a/examples/astro/payload/package.json b/examples/astro/payload/package.json index 57c94b749a2..a92e87cab68 100644 --- a/examples/astro/payload/package.json +++ b/examples/astro/payload/package.json @@ -27,7 +27,7 @@ "@payloadcms/richtext-lexical": "3.11.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "15.4.9", + "next": "15.4.10", "payload": "3.11.0", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/examples/astro/payload/pnpm-lock.yaml b/examples/astro/payload/pnpm-lock.yaml index 4a1f562a6fb..7525bd8173f 100644 --- a/examples/astro/payload/pnpm-lock.yaml +++ b/examples/astro/payload/pnpm-lock.yaml @@ -13,10 +13,10 @@ importers: version: 3.11.0(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)) '@payloadcms/next': specifier: 3.11.0 - version: 3.11.0(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + version: 3.11.0(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) '@payloadcms/richtext-lexical': specifier: 3.11.0 - version: 3.11.0(0d028be8ae31e9f10c1ea354cfbea024) + version: 3.11.0(b8bee0da390ff073984722ec42191f87) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -24,8 +24,8 @@ importers: specifier: ^16.8.1 version: 16.12.0 next: - specifier: 15.4.9 - version: 15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.10 + version: 15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: 3.11.0 version: 3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) @@ -673,8 +673,8 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@next/env@15.4.9': - resolution: {integrity: sha512-OYR0RulK5phnbxxzcLE4/ECgfx1PL3EHrDbjyelJ7jauaO+/Qvj5gG8JPMltB51CygC2KrZ0aAfYLjPYjYY17A==} + '@next/env@15.4.10': + resolution: {integrity: sha512-knhmoJ0Vv7VRf6pZEPSnciUG1S4bIhWx+qTYBW/AjxEtlzsiNORPk8sFDCEvqLfmKuey56UB9FL1UdHEV3uBrg==} '@next/env@15.5.8': resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} @@ -2288,8 +2288,8 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next@15.4.9: - resolution: {integrity: sha512-/NedNmbiH4Umt/7SohT9VKxEdBt02Lj33xHrukE7d8Li6juT+75sEq4a4U06jggrvdbklKgr78OZEyWZ8XRrtw==} + next@15.4.10: + resolution: {integrity: sha512-itVlc79QjpKMFMRhP+kbGKaSG/gZM6RCvwhEbwmCNF06CdDiNaoHcbeg0PqkEa2GOcn8KJ0nnc7+yL7EjoYLHQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -3688,7 +3688,7 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@next/env@15.4.9': {} + '@next/env@15.4.10': {} '@next/env@15.5.8': {} @@ -3764,19 +3764,19 @@ snapshots: transitivePeerDependencies: - typescript - '@payloadcms/next@3.11.0(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)': + '@payloadcms/next@3.11.0(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)': dependencies: '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@payloadcms/graphql': 3.11.0(graphql@16.12.0)(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(typescript@5.7.2) '@payloadcms/translations': 3.11.0 - '@payloadcms/ui': 3.11.0(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + '@payloadcms/ui': 3.11.0(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) busboy: 1.6.0 file-type: 19.3.0 graphql: 16.12.0 graphql-http: 1.22.4(graphql@16.12.0) graphql-playground-html: 1.6.30 http-status: 1.6.2 - next: 15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) path-to-regexp: 6.3.0 payload: 3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) qs-esm: 7.0.2 @@ -3792,7 +3792,7 @@ snapshots: - supports-color - typescript - '@payloadcms/richtext-lexical@3.11.0(0d028be8ae31e9f10c1ea354cfbea024)': + '@payloadcms/richtext-lexical@3.11.0(b8bee0da390ff073984722ec42191f87)': dependencies: '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -3806,9 +3806,9 @@ snapshots: '@lexical/selection': 0.20.0 '@lexical/table': 0.20.0 '@lexical/utils': 0.20.0 - '@payloadcms/next': 3.11.0(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + '@payloadcms/next': 3.11.0(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) '@payloadcms/translations': 3.11.0 - '@payloadcms/ui': 3.11.0(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + '@payloadcms/ui': 3.11.0(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -3835,7 +3835,7 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.11.0(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)': + '@payloadcms/ui@3.11.0(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)': dependencies: '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) @@ -3849,7 +3849,7 @@ snapshots: date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) object-to-formdata: 4.5.1 payload: 3.11.0(graphql@16.12.0)(monaco-editor@0.55.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) qs-esm: 7.0.2 @@ -5621,9 +5621,9 @@ snapshots: natural-compare@1.4.0: {} - next@15.4.9(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.4.9 + '@next/env': 15.4.10 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001760 postcss: 8.4.31 diff --git a/examples/astro/pnpm-lock.yaml b/examples/astro/pnpm-lock.yaml index 6d7ace21970..175feb3a676 100644 --- a/examples/astro/pnpm-lock.yaml +++ b/examples/astro/pnpm-lock.yaml @@ -15,10 +15,10 @@ importers: version: 3.11.0(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)) '@payloadcms/next': specifier: 3.11.0 - version: 3.11.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.4.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + version: 3.11.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) '@payloadcms/richtext-lexical': specifier: 3.11.0 - version: 3.11.0(5b012d7ae2e0cc1fc995938474076b3e) + version: 3.11.0(976205ac25b293413cc01e462676376b) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -26,8 +26,8 @@ importers: specifier: ^16.8.1 version: 16.10.0 next: - specifier: 15.4.8 - version: 15.4.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.10 + version: 15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: 3.11.0 version: 3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) @@ -48,11 +48,11 @@ importers: specifier: ^22.5.4 version: 22.10.2 '@types/react': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1 '@types/react-dom': - specifier: 19.0.1 - version: 19.0.1 + specifier: 19.2.1 + version: 19.2.1(@types/react@19.2.1) eslint: specifier: ^9.16.0 version: 9.17.0(jiti@2.4.2) @@ -1096,8 +1096,8 @@ packages: '@next/env@15.1.2': resolution: {integrity: sha512-Hm3jIGsoUl6RLB1vzY+dZeqb+/kWPZ+h34yiWxW0dV87l8Im/eMOwpOA+a0L78U0HM04syEjXuRlCozqpwuojQ==} - '@next/env@15.4.8': - resolution: {integrity: sha512-LydLa2MDI1NMrOFSkO54mTc8iIHSttj6R6dthITky9ylXV2gCGi0bHQjVCtLGRshdRPjyh2kXbxJukDtBWQZtQ==} + '@next/env@15.4.10': + resolution: {integrity: sha512-knhmoJ0Vv7VRf6pZEPSnciUG1S4bIhWx+qTYBW/AjxEtlzsiNORPk8sFDCEvqLfmKuey56UB9FL1UdHEV3uBrg==} '@next/eslint-plugin-next@15.1.0': resolution: {integrity: sha512-+jPT0h+nelBT6HC9ZCHGc7DgGVy04cv4shYdAe6tKlEbjQUtwU3LzQhzbDHQyY2m6g39m6B0kOFVuLGBrxxbGg==} @@ -1488,16 +1488,18 @@ packages: '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/react-dom@19.0.1': - resolution: {integrity: sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 '@types/react-transition-group@4.4.12': resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} peerDependencies: '@types/react': '*' - '@types/react@19.0.1': - resolution: {integrity: sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -3207,8 +3209,8 @@ packages: resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} engines: {node: '>= 10'} - next@15.4.8: - resolution: {integrity: sha512-jwOXTz/bo0Pvlf20FSb6VXVeWRssA2vbvq9SdrOPEg9x8E1B27C2rQtvriAn600o9hH61kjrVRexEffv3JybuA==} + next@15.4.10: + resolution: {integrity: sha512-itVlc79QjpKMFMRhP+kbGKaSG/gZM6RCvwhEbwmCNF06CdDiNaoHcbeg0PqkEa2GOcn8KJ0nnc7+yL7EjoYLHQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -4603,7 +4605,7 @@ snapshots: '@emotion/memoize@0.9.0': {} - '@emotion/react@11.14.0(@types/react@19.0.1)(react@19.2.1)': + '@emotion/react@11.14.0(@types/react@19.2.1)(react@19.2.1)': dependencies: '@babel/runtime': 7.26.0 '@emotion/babel-plugin': 11.13.5 @@ -4615,7 +4617,7 @@ snapshots: hoist-non-react-statics: 3.3.2 react: 19.2.1 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 transitivePeerDependencies: - supports-color @@ -5309,7 +5311,7 @@ snapshots: '@next/env@15.1.2': {} - '@next/env@15.4.8': {} + '@next/env@15.4.10': {} '@next/eslint-plugin-next@15.1.0': dependencies: @@ -5450,19 +5452,19 @@ snapshots: transitivePeerDependencies: - typescript - '@payloadcms/next@3.11.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.4.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)': + '@payloadcms/next@3.11.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)': dependencies: '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@payloadcms/graphql': 3.11.0(graphql@16.10.0)(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(typescript@5.7.2) '@payloadcms/translations': 3.11.0 - '@payloadcms/ui': 3.11.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.4.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + '@payloadcms/ui': 3.11.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) busboy: 1.6.0 file-type: 19.3.0 graphql: 16.10.0 graphql-http: 1.22.3(graphql@16.10.0) graphql-playground-html: 1.6.30 http-status: 1.6.2 - next: 15.4.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) path-to-regexp: 6.3.0 payload: 3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) qs-esm: 7.0.2 @@ -5478,7 +5480,7 @@ snapshots: - supports-color - typescript - '@payloadcms/richtext-lexical@3.11.0(5b012d7ae2e0cc1fc995938474076b3e)': + '@payloadcms/richtext-lexical@3.11.0(976205ac25b293413cc01e462676376b)': dependencies: '@faceless-ui/modal': 3.0.0-beta.2(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@faceless-ui/scroll-info': 2.0.0-beta.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -5492,9 +5494,9 @@ snapshots: '@lexical/selection': 0.20.0 '@lexical/table': 0.20.0 '@lexical/utils': 0.20.0 - '@payloadcms/next': 3.11.0(@types/react@19.0.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.4.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + '@payloadcms/next': 3.11.0(@types/react@19.2.1)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) '@payloadcms/translations': 3.11.0 - '@payloadcms/ui': 3.11.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.4.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) + '@payloadcms/ui': 3.11.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -5521,7 +5523,7 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.11.0(@types/react@19.0.1)(monaco-editor@0.52.2)(next@15.4.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)': + '@payloadcms/ui@3.11.0(@types/react@19.2.1)(monaco-editor@0.52.2)(next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(payload@3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2)': dependencies: '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@dnd-kit/sortable': 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) @@ -5535,7 +5537,7 @@ snapshots: date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.4.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) object-to-formdata: 4.5.1 payload: 3.11.0(graphql@16.10.0)(monaco-editor@0.52.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.7.2) qs-esm: 7.0.2 @@ -5543,7 +5545,7 @@ snapshots: react-datepicker: 7.5.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) react-dom: 19.2.1(react@19.2.1) react-image-crop: 10.1.8(react@19.2.1) - react-select: 5.9.0(@types/react@19.0.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react-select: 5.9.0(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) scheduler: 0.25.0 sonner: 1.7.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) ts-essentials: 10.0.3(typescript@5.7.2) @@ -5703,15 +5705,15 @@ snapshots: '@types/parse-json@4.0.2': {} - '@types/react-dom@19.0.1': + '@types/react-dom@19.2.1(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@types/react-transition-group@4.4.12(@types/react@19.0.1)': + '@types/react-transition-group@4.4.12(@types/react@19.2.1)': dependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 - '@types/react@19.0.1': + '@types/react@19.2.1': dependencies: csstype: 3.1.3 @@ -7972,9 +7974,9 @@ snapshots: neotraverse@0.6.18: {} - next@15.4.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.10(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.4.8 + '@next/env': 15.4.10 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001690 postcss: 8.4.31 @@ -8399,19 +8401,19 @@ snapshots: react-is@16.13.1: {} - react-select@5.9.0(@types/react@19.0.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + react-select@5.9.0(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: '@babel/runtime': 7.26.0 '@emotion/cache': 11.14.0 - '@emotion/react': 11.14.0(@types/react@19.0.1)(react@19.2.1) + '@emotion/react': 11.14.0(@types/react@19.2.1)(react@19.2.1) '@floating-ui/dom': 1.6.12 - '@types/react-transition-group': 4.4.12(@types/react@19.0.1) + '@types/react-transition-group': 4.4.12(@types/react@19.2.1) memoize-one: 6.0.0 prop-types: 15.8.1 react: 19.2.1 react-dom: 19.2.1(react@19.2.1) react-transition-group: 4.4.5(react-dom@19.2.1(react@19.2.1))(react@19.2.1) - use-isomorphic-layout-effect: 1.2.0(@types/react@19.0.1)(react@19.2.1) + use-isomorphic-layout-effect: 1.2.0(@types/react@19.2.1)(react@19.2.1) transitivePeerDependencies: - '@types/react' - supports-color @@ -9227,11 +9229,11 @@ snapshots: react: 19.2.1 scheduler: 0.25.0 - use-isomorphic-layout-effect@1.2.0(@types/react@19.0.1)(react@19.2.1): + use-isomorphic-layout-effect@1.2.0(@types/react@19.2.1)(react@19.2.1): dependencies: react: 19.2.1 optionalDependencies: - '@types/react': 19.0.1 + '@types/react': 19.2.1 utf8-byte-length@1.0.5: {} diff --git a/examples/auth/package.json b/examples/auth/package.json index 2f632f2ca54..c51ace9cba3 100644 --- a/examples/auth/package.json +++ b/examples/auth/package.json @@ -21,7 +21,7 @@ "@payloadcms/richtext-slate": "latest", "@payloadcms/ui": "latest", "cross-env": "^7.0.3", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "latest", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/examples/auth/pnpm-lock.yaml b/examples/auth/pnpm-lock.yaml index 7decdd681f2..b33c54a62a5 100644 --- a/examples/auth/pnpm-lock.yaml +++ b/examples/auth/pnpm-lock.yaml @@ -24,7 +24,7 @@ importers: specifier: ^7.0.3 version: 7.0.3 next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: latest @@ -2191,6 +2191,7 @@ packages: next@15.5.8: resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 diff --git a/examples/custom-components/package.json b/examples/custom-components/package.json index 9a458fa5246..9ad567a4deb 100644 --- a/examples/custom-components/package.json +++ b/examples/custom-components/package.json @@ -25,7 +25,7 @@ "dotenv": "^8.2.0", "graphql": "^16.9.0", "install": "^0.13.0", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1" diff --git a/examples/custom-components/pnpm-lock.yaml b/examples/custom-components/pnpm-lock.yaml index e0891970115..d1558b2c7ef 100644 --- a/examples/custom-components/pnpm-lock.yaml +++ b/examples/custom-components/pnpm-lock.yaml @@ -36,7 +36,7 @@ importers: specifier: ^0.13.0 version: 0.13.0 next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest @@ -2148,6 +2148,7 @@ packages: next@15.5.8: resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -4341,7 +4342,7 @@ snapshots: '@typescript-eslint/parser': 8.21.0(eslint@8.57.1)(typescript@5.5.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.4(eslint@8.57.1) @@ -4361,7 +4362,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0 @@ -4377,14 +4378,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.21.0(eslint@8.57.1)(typescript@5.5.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -4399,7 +4400,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.21.0(eslint@8.57.1)(typescript@5.5.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 diff --git a/examples/custom-server/package.json b/examples/custom-server/package.json index ea0def6af34..a61f9a5c45d 100644 --- a/examples/custom-server/package.json +++ b/examples/custom-server/package.json @@ -17,7 +17,7 @@ "cross-env": "^7.0.3", "express": "^4.21.1", "graphql": "^16.8.1", - "next": "15.4.9", + "next": "15.4.10", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1" diff --git a/examples/custom-server/pnpm-lock.yaml b/examples/custom-server/pnpm-lock.yaml index fb363cdba6f..78e52c153c1 100644 --- a/examples/custom-server/pnpm-lock.yaml +++ b/examples/custom-server/pnpm-lock.yaml @@ -13,13 +13,13 @@ importers: version: 3.68.2(@aws-sdk/credential-providers@3.948.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3)) '@payloadcms/next': specifier: latest - version: 3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + version: 3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) '@payloadcms/payload-cloud': specifier: latest version: 3.68.2(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3)) '@payloadcms/richtext-lexical': specifier: latest - version: 3.68.2(@faceless-ui/modal@3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)(yjs@13.6.27) + version: 3.68.2(@faceless-ui/modal@3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)(yjs@13.6.27) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -30,8 +30,8 @@ importers: specifier: ^16.8.1 version: 16.12.0 next: - specifier: 15.4.9 - version: 15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + specifier: 15.4.10 + version: 15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest version: 3.68.2(graphql@16.12.0)(typescript@5.9.3) @@ -974,8 +974,8 @@ packages: '@mongodb-js/saslprep@1.4.0': resolution: {integrity: sha512-ZHzx7Z3rdlWL1mECydvpryWN/ETXJiCxdgQKTAH+djzIPe77HdnSizKBDi1TVDXZjXyOj2IqEG/vPw71ULF06w==} - '@next/env@15.4.9': - resolution: {integrity: sha512-OYR0RulK5phnbxxzcLE4/ECgfx1PL3EHrDbjyelJ7jauaO+/Qvj5gG8JPMltB51CygC2KrZ0aAfYLjPYjYY17A==} + '@next/env@15.4.10': + resolution: {integrity: sha512-knhmoJ0Vv7VRf6pZEPSnciUG1S4bIhWx+qTYBW/AjxEtlzsiNORPk8sFDCEvqLfmKuey56UB9FL1UdHEV3uBrg==} '@next/env@15.5.8': resolution: {integrity: sha512-ejZHa3ogTxcy851dFoNtfB5B2h7AbSAtHbR5CymUlnz4yW1QjHNufVpvTu8PTnWBKFKjrd4k6Gbi2SsCiJKvxw==} @@ -2233,8 +2233,8 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - next@15.4.9: - resolution: {integrity: sha512-/NedNmbiH4Umt/7SohT9VKxEdBt02Lj33xHrukE7d8Li6juT+75sEq4a4U06jggrvdbklKgr78OZEyWZ8XRrtw==} + next@15.4.10: + resolution: {integrity: sha512-itVlc79QjpKMFMRhP+kbGKaSG/gZM6RCvwhEbwmCNF06CdDiNaoHcbeg0PqkEa2GOcn8KJ0nnc7+yL7EjoYLHQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -4124,7 +4124,7 @@ snapshots: dependencies: sparse-bitfield: 3.0.3 - '@next/env@15.4.9': {} + '@next/env@15.4.10': {} '@next/env@15.5.8': {} @@ -4185,12 +4185,12 @@ snapshots: transitivePeerDependencies: - typescript - '@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)': + '@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)': dependencies: '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@payloadcms/graphql': 3.68.2(graphql@16.12.0)(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(typescript@5.9.3) '@payloadcms/translations': 3.68.2 - '@payloadcms/ui': 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + '@payloadcms/ui': 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) busboy: 1.6.0 dequal: 2.0.3 file-type: 19.3.0 @@ -4198,7 +4198,7 @@ snapshots: graphql-http: 1.22.4(graphql@16.12.0) graphql-playground-html: 1.6.30 http-status: 2.1.0 - next: 15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + next: 15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) path-to-regexp: 6.3.0 payload: 3.68.2(graphql@16.12.0)(typescript@5.9.3) qs-esm: 7.0.2 @@ -4226,7 +4226,7 @@ snapshots: - aws-crt - encoding - '@payloadcms/richtext-lexical@3.68.2(@faceless-ui/modal@3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)(yjs@13.6.27)': + '@payloadcms/richtext-lexical@3.68.2(@faceless-ui/modal@3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@faceless-ui/scroll-info@2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2))(@payloadcms/next@3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3))(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)(yjs@13.6.27)': dependencies: '@faceless-ui/modal': 3.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) '@faceless-ui/scroll-info': 2.0.0(react-dom@19.2.2(react@19.2.2))(react@19.2.2) @@ -4241,9 +4241,9 @@ snapshots: '@lexical/selection': 0.35.0 '@lexical/table': 0.35.0 '@lexical/utils': 0.35.0 - '@payloadcms/next': 3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + '@payloadcms/next': 3.68.2(@types/react@19.2.1)(graphql@16.12.0)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) '@payloadcms/translations': 3.68.2 - '@payloadcms/ui': 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) + '@payloadcms/ui': 3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3) '@types/uuid': 10.0.0 acorn: 8.12.1 bson-objectid: 2.0.4 @@ -4274,7 +4274,7 @@ snapshots: dependencies: date-fns: 4.1.0 - '@payloadcms/ui@3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)': + '@payloadcms/ui@3.68.2(@types/react@19.2.1)(monaco-editor@0.55.1)(next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4))(payload@3.68.2(graphql@16.12.0)(typescript@5.9.3))(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(typescript@5.9.3)': dependencies: '@date-fns/tz': 1.2.0 '@dnd-kit/core': 6.0.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2) @@ -4289,7 +4289,7 @@ snapshots: date-fns: 4.1.0 dequal: 2.0.3 md5: 2.3.0 - next: 15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) + next: 15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) object-to-formdata: 4.5.1 payload: 3.68.2(graphql@16.12.0)(typescript@5.9.3) qs-esm: 7.0.2 @@ -5720,9 +5720,9 @@ snapshots: negotiator@0.6.3: {} - next@15.4.9(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): + next@15.4.10(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4): dependencies: - '@next/env': 15.4.9 + '@next/env': 15.4.10 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001760 postcss: 8.4.31 diff --git a/examples/draft-preview/package.json b/examples/draft-preview/package.json index 7651748c626..b57d0ebe5da 100644 --- a/examples/draft-preview/package.json +++ b/examples/draft-preview/package.json @@ -24,7 +24,7 @@ "dotenv": "^8.2.0", "escape-html": "^1.0.3", "graphql": "^16.9.0", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "latest", "react": "19.2.1", "react-dom": "19.2.1" diff --git a/examples/draft-preview/pnpm-lock.yaml b/examples/draft-preview/pnpm-lock.yaml index 511883cc723..9de94989330 100644 --- a/examples/draft-preview/pnpm-lock.yaml +++ b/examples/draft-preview/pnpm-lock.yaml @@ -33,7 +33,7 @@ importers: specifier: ^16.9.0 version: 16.10.0 next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: latest @@ -2068,6 +2068,7 @@ packages: next@15.5.8: resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 diff --git a/examples/email/package.json b/examples/email/package.json index ded982f1cb0..7446c3c0fd7 100644 --- a/examples/email/package.json +++ b/examples/email/package.json @@ -25,7 +25,7 @@ "ejs": "3.1.10", "graphql": "^16.9.0", "juice": "11.0.0", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1" diff --git a/examples/email/pnpm-lock.yaml b/examples/email/pnpm-lock.yaml index 674b157325a..e0235a9f312 100644 --- a/examples/email/pnpm-lock.yaml +++ b/examples/email/pnpm-lock.yaml @@ -39,7 +39,7 @@ importers: specifier: 11.0.0 version: 11.0.0 next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest @@ -2249,6 +2249,7 @@ packages: next@15.5.8: resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 diff --git a/examples/form-builder/package.json b/examples/form-builder/package.json index a48bb55198d..49cc96cbe62 100644 --- a/examples/form-builder/package.json +++ b/examples/form-builder/package.json @@ -25,7 +25,7 @@ "@payloadcms/richtext-lexical": "latest", "cross-env": "^7.0.3", "graphql": "^16.9.0", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "latest", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/examples/form-builder/pnpm-lock.yaml b/examples/form-builder/pnpm-lock.yaml index 1907edd79b8..48b0619e57d 100644 --- a/examples/form-builder/pnpm-lock.yaml +++ b/examples/form-builder/pnpm-lock.yaml @@ -39,7 +39,7 @@ importers: specifier: ^16.9.0 version: 16.9.0 next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: latest @@ -2568,6 +2568,7 @@ packages: next@15.5.8: resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 diff --git a/examples/live-preview/package.json b/examples/live-preview/package.json index 62a0cb59b47..3f4373c8e9f 100644 --- a/examples/live-preview/package.json +++ b/examples/live-preview/package.json @@ -27,7 +27,7 @@ "dotenv": "^8.2.0", "escape-html": "^1.0.3", "graphql": "^16.9.0", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1", diff --git a/examples/live-preview/pnpm-lock.yaml b/examples/live-preview/pnpm-lock.yaml index 35f1734b29a..5d45466194a 100644 --- a/examples/live-preview/pnpm-lock.yaml +++ b/examples/live-preview/pnpm-lock.yaml @@ -36,7 +36,7 @@ importers: specifier: ^16.9.0 version: 16.11.0 next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest @@ -2186,6 +2186,7 @@ packages: next@15.5.8: resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 diff --git a/examples/localization/package.json b/examples/localization/package.json index 3153b964a1f..77d09e3c492 100644 --- a/examples/localization/package.json +++ b/examples/localization/package.json @@ -39,7 +39,7 @@ "graphql": "^16.8.2", "jsonwebtoken": "9.0.2", "lucide-react": "^0.378.0", - "next": "^15.4.9", + "next": "^15.4.10", "next-intl": "^3.23.2", "payload": "latest", "prism-react-renderer": "^2.3.1", diff --git a/examples/localization/pnpm-lock.yaml b/examples/localization/pnpm-lock.yaml index db6c9cc82ef..4759c552947 100644 --- a/examples/localization/pnpm-lock.yaml +++ b/examples/localization/pnpm-lock.yaml @@ -75,7 +75,7 @@ importers: specifier: ^0.378.0 version: 0.378.0(react@19.2.2) next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.4(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) next-intl: specifier: ^3.23.2 diff --git a/examples/multi-tenant/package.json b/examples/multi-tenant/package.json index 5670616d4e4..23cc51071c9 100644 --- a/examples/multi-tenant/package.json +++ b/examples/multi-tenant/package.json @@ -25,7 +25,7 @@ "cross-env": "^7.0.3", "dotenv": "^8.2.0", "graphql": "^16.9.0", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "latest", "qs-esm": "7.0.2", "react": "^19.2.1", diff --git a/examples/multi-tenant/pnpm-lock.yaml b/examples/multi-tenant/pnpm-lock.yaml index 0eaed6b540b..1437a3e41e1 100644 --- a/examples/multi-tenant/pnpm-lock.yaml +++ b/examples/multi-tenant/pnpm-lock.yaml @@ -36,7 +36,7 @@ importers: specifier: ^16.9.0 version: 16.10.0 next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest @@ -2801,6 +2801,7 @@ packages: next@15.5.8: resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 diff --git a/examples/remix/payload/package.json b/examples/remix/payload/package.json index d9cb846f59a..5816e234d15 100644 --- a/examples/remix/payload/package.json +++ b/examples/remix/payload/package.json @@ -27,7 +27,7 @@ "@payloadcms/richtext-lexical": "latest", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1", diff --git a/examples/remix/payload/pnpm-lock.yaml b/examples/remix/payload/pnpm-lock.yaml index 026a809729b..a3ee917a0bc 100644 --- a/examples/remix/payload/pnpm-lock.yaml +++ b/examples/remix/payload/pnpm-lock.yaml @@ -24,7 +24,7 @@ importers: specifier: ^16.8.1 version: 16.12.0 next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest @@ -2288,6 +2288,7 @@ packages: next@15.5.8: resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 diff --git a/examples/tailwind-shadcn-ui/package.json b/examples/tailwind-shadcn-ui/package.json index 07db4247f62..3ba568f1869 100644 --- a/examples/tailwind-shadcn-ui/package.json +++ b/examples/tailwind-shadcn-ui/package.json @@ -21,7 +21,7 @@ "clsx": "^2.1.1", "cross-env": "^7.0.3", "lucide-react": "^0.376.0", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "beta", "react": "^19.2.1", "react-dom": "^19.2.1", diff --git a/examples/tailwind-shadcn-ui/pnpm-lock.yaml b/examples/tailwind-shadcn-ui/pnpm-lock.yaml index c33a140671b..6adae87bcea 100644 --- a/examples/tailwind-shadcn-ui/pnpm-lock.yaml +++ b/examples/tailwind-shadcn-ui/pnpm-lock.yaml @@ -30,7 +30,7 @@ importers: specifier: ^0.376.0 version: 0.376.0(react@19.2.2) next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: beta @@ -1763,6 +1763,7 @@ packages: next@15.5.8: resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 diff --git a/examples/whitelabel/package.json b/examples/whitelabel/package.json index 93597e02453..1bac2764ebd 100644 --- a/examples/whitelabel/package.json +++ b/examples/whitelabel/package.json @@ -20,7 +20,7 @@ "@payloadcms/richtext-lexical": "latest", "cross-env": "^7.0.3", "graphql": "^16.9.0", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "latest", "react": "^19.2.1", "react-dom": "^19.2.1", diff --git a/examples/whitelabel/pnpm-lock.yaml b/examples/whitelabel/pnpm-lock.yaml index b310a5d66c3..8625a0ff572 100644 --- a/examples/whitelabel/pnpm-lock.yaml +++ b/examples/whitelabel/pnpm-lock.yaml @@ -24,7 +24,7 @@ importers: specifier: ^16.9.0 version: 16.9.0 next: - specifier: ^15.4.9 + specifier: ^15.4.10 version: 15.5.8(react-dom@19.2.2(react@19.2.2))(react@19.2.2)(sass@1.77.4) payload: specifier: latest @@ -2123,6 +2123,7 @@ packages: next@15.5.8: resolution: {integrity: sha512-Tma2R50eiM7Fx6fbDeHiThq7sPgl06mBr76j6Ga0lMFGrmaLitFsy31kykgb8Z++DR2uIEKi2RZ0iyjIwFd15Q==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 diff --git a/package.json b/package.json index cc0f0fb202a..28f0b745430 100644 --- a/package.json +++ b/package.json @@ -180,7 +180,7 @@ "minimist": "1.2.8", "mongodb-memory-server": "10.1.4", "mongoose": "8.15.1", - "next": "15.4.9", + "next": "15.4.10", "open": "^10.1.0", "p-limit": "^5.0.0", "pg": "8.16.3", diff --git a/packages/next/package.json b/packages/next/package.json index ba90d8b09f3..832da42f99f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -143,7 +143,7 @@ }, "peerDependencies": { "graphql": "^16.8.1", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "workspace:*" }, "engines": { diff --git a/packages/ui/package.json b/packages/ui/package.json index 8b138b06ed4..c77dfefc5aa 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -178,7 +178,7 @@ "payload": "workspace:*" }, "peerDependencies": { - "next": "^15.2.7 || ^15.3.7 || ^15.4.9 || ^15.5.8", + "next": "^15.2.8 || ^15.3.8 || ^15.4.10 || ^15.5.9", "payload": "workspace:*", "react": "^19.0.1 || ^19.1.2 || ^19.2.1", "react-dom": "^19.0.1 || ^19.1.2 || ^19.2.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0325fe7419f..fc8c92a6c8c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,7 +47,7 @@ importers: version: 1.56.1 '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) '@sentry/node': specifier: ^8.33.1 version: 8.37.1 @@ -145,8 +145,8 @@ importers: specifier: 8.15.1 version: 8.15.1(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: - specifier: 15.4.9 - version: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.10 + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) open: specifier: ^10.1.0 version: 10.1.0 @@ -803,8 +803,8 @@ importers: specifier: 2.1.0 version: 2.1.0 next: - specifier: ^15.4.9 - version: 15.4.9(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: ^15.4.10 + version: 15.4.10(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) path-to-regexp: specifier: 6.3.0 version: 6.3.0 @@ -1762,8 +1762,8 @@ importers: specifier: 2.3.0 version: 2.3.0 next: - specifier: ^15.2.7 || ^15.3.7 || ^15.4.9 || ^15.5.8 - version: 15.4.9(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: ^15.2.8 || ^15.3.8 || ^15.4.10 || ^15.5.9 + version: 15.4.10(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) object-to-formdata: specifier: 4.5.1 version: 4.5.1 @@ -1868,8 +1868,8 @@ importers: specifier: ^16.8.1 version: 16.9.0 next: - specifier: 15.4.9 - version: 15.4.9(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.10 + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: workspace:* version: link:../../packages/payload @@ -2011,7 +2011,7 @@ importers: version: 8.6.0(react@19.2.1) geist: specifier: ^1.3.0 - version: 1.4.2(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.4.2(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) graphql: specifier: ^16.8.1 version: 16.9.0 @@ -2022,8 +2022,8 @@ importers: specifier: ^0.477.0 version: 0.477.0(react@19.2.1) next: - specifier: 15.4.9 - version: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.10 + version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes: specifier: 0.4.6 version: 0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -2210,7 +2210,7 @@ importers: version: 16.4.7 geist: specifier: ^1.3.0 - version: 1.4.2(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) graphql: specifier: ^16.8.1 version: 16.9.0 @@ -2218,11 +2218,11 @@ importers: specifier: ^0.378.0 version: 0.378.0(react@19.2.1) next: - specifier: 15.4.9 - version: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.10 + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-sitemap: specifier: ^4.2.3 - version: 4.2.3(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 4.2.3(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) payload: specifier: workspace:* version: link:../../packages/payload @@ -2463,7 +2463,7 @@ importers: version: link:../packages/ui '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) '@sentry/react': specifier: ^7.77.0 version: 7.119.2(react@19.2.1) @@ -2534,8 +2534,8 @@ importers: specifier: 8.15.1 version: 8.15.1(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: - specifier: 15.4.9 - version: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + specifier: 15.4.10 + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) nodemailer: specifier: 7.0.9 version: 7.0.9 @@ -5732,12 +5732,12 @@ packages: '@next/env@15.2.0': resolution: {integrity: sha512-eMgJu1RBXxxqqnuRJQh5RozhskoNUDHBFybvi+Z+yK9qzKeG7dadhv/Vp1YooSZmCnegf7JxWuapV77necLZNA==} + '@next/env@15.4.10': + resolution: {integrity: sha512-knhmoJ0Vv7VRf6pZEPSnciUG1S4bIhWx+qTYBW/AjxEtlzsiNORPk8sFDCEvqLfmKuey56UB9FL1UdHEV3uBrg==} + '@next/env@15.4.7': resolution: {integrity: sha512-PrBIpO8oljZGTOe9HH0miix1w5MUiGJ/q83Jge03mHEE0E3pyqzAy2+l5G6aJDbXoobmxPJTVhbCuwlLtjSHwg==} - '@next/env@15.4.9': - resolution: {integrity: sha512-OYR0RulK5phnbxxzcLE4/ECgfx1PL3EHrDbjyelJ7jauaO+/Qvj5gG8JPMltB51CygC2KrZ0aAfYLjPYjYY17A==} - '@next/env@15.5.4': resolution: {integrity: sha512-27SQhYp5QryzIT5uO8hq99C69eLQ7qkzkDPsk3N+GuS2XgOgoYEeOav7Pf8Tn4drECOVDsDg8oj+/DVy8qQL2A==} @@ -12182,8 +12182,8 @@ packages: react: 19.2.1 react-dom: 19.2.1 - next@15.4.9: - resolution: {integrity: sha512-/NedNmbiH4Umt/7SohT9VKxEdBt02Lj33xHrukE7d8Li6juT+75sEq4a4U06jggrvdbklKgr78OZEyWZ8XRrtw==} + next@15.4.10: + resolution: {integrity: sha512-itVlc79QjpKMFMRhP+kbGKaSG/gZM6RCvwhEbwmCNF06CdDiNaoHcbeg0PqkEa2GOcn8KJ0nnc7+yL7EjoYLHQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -19280,9 +19280,9 @@ snapshots: '@next/env@15.2.0': {} - '@next/env@15.4.7': {} + '@next/env@15.4.10': {} - '@next/env@15.4.9': {} + '@next/env@15.4.7': {} '@next/env@15.5.4': {} @@ -20450,7 +20450,7 @@ snapshots: '@sentry/utils': 7.119.2 localforage: 1.10.0 - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -20466,7 +20466,7 @@ snapshots: '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.15.3)) chalk: 3.0.0 - next: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -25092,9 +25092,13 @@ snapshots: - encoding - supports-color - geist@1.4.2(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + geist@1.4.2(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + dependencies: + next: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + + geist@1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: - next: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) gel@2.0.1: dependencies: @@ -27036,22 +27040,22 @@ snapshots: transitivePeerDependencies: - supports-color - next-sitemap@4.2.3(next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + next-sitemap@4.2.3(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: '@corex/deepmerge': 4.0.43 '@next/env': 13.5.11 fast-glob: 3.3.2 minimist: 1.2.8 - next: 15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes@0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: react: 19.2.1 react-dom: 19.2.1(react@19.2.1) - next@15.4.9(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.10(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.4.9 + '@next/env': 15.4.10 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001720 postcss: 8.4.31 @@ -27076,9 +27080,9 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.4.9(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.4.9 + '@next/env': 15.4.10 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001720 postcss: 8.4.31 @@ -27102,9 +27106,9 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.4.9(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: - '@next/env': 15.4.9 + '@next/env': 15.4.10 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001720 postcss: 8.4.31 diff --git a/templates/_template/package.json b/templates/_template/package.json index bef60ef5dab..59650e62827 100644 --- a/templates/_template/package.json +++ b/templates/_template/package.json @@ -24,7 +24,7 @@ "@payloadcms/ui": "latest", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "15.4.9", + "next": "15.4.10", "payload": "latest", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/templates/blank/package.json b/templates/blank/package.json index 738eed3d09a..4d49f1490d0 100644 --- a/templates/blank/package.json +++ b/templates/blank/package.json @@ -25,7 +25,7 @@ "cross-env": "^7.0.3", "dotenv": "16.4.7", "graphql": "^16.8.1", - "next": "15.4.9", + "next": "15.4.10", "payload": "workspace:*", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/templates/ecommerce/package.json b/templates/ecommerce/package.json index 01f9a04765b..6dd7561fde1 100644 --- a/templates/ecommerce/package.json +++ b/templates/ecommerce/package.json @@ -52,7 +52,7 @@ "graphql": "^16.8.2", "jsonwebtoken": "9.0.1", "lucide-react": "^0.477.0", - "next": "15.4.9", + "next": "15.4.10", "next-themes": "0.4.6", "payload": "workspace:*", "prism-react-renderer": "^2.3.1", diff --git a/templates/plugin/package.json b/templates/plugin/package.json index c4c868b3dee..547279f7a82 100644 --- a/templates/plugin/package.json +++ b/templates/plugin/package.json @@ -65,7 +65,7 @@ "eslint-config-next": "15.4.7", "graphql": "^16.8.1", "mongodb-memory-server": "10.1.4", - "next": "15.4.9", + "next": "15.4.10", "open": "^10.1.0", "payload": "3.37.0", "prettier": "^3.4.2", diff --git a/templates/website/package.json b/templates/website/package.json index d8952ca4248..3d7427bd101 100644 --- a/templates/website/package.json +++ b/templates/website/package.json @@ -44,7 +44,7 @@ "geist": "^1.3.0", "graphql": "^16.8.2", "lucide-react": "^0.378.0", - "next": "15.4.9", + "next": "15.4.10", "next-sitemap": "^4.2.3", "payload": "workspace:*", "prism-react-renderer": "^2.3.1", diff --git a/templates/with-cloudflare-d1/package.json b/templates/with-cloudflare-d1/package.json index 22bfe347c3a..e208eecbea6 100644 --- a/templates/with-cloudflare-d1/package.json +++ b/templates/with-cloudflare-d1/package.json @@ -34,7 +34,7 @@ "cross-env": "^7.0.3", "dotenv": "16.4.7", "graphql": "^16.8.1", - "next": "15.4.9", + "next": "15.4.10", "payload": "3.63.0", "react": "19.2.1", "react-dom": "19.2.1" diff --git a/templates/with-postgres/package.json b/templates/with-postgres/package.json index b2de7db291a..69e022dd539 100644 --- a/templates/with-postgres/package.json +++ b/templates/with-postgres/package.json @@ -25,7 +25,7 @@ "@payloadcms/ui": "3.63.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "15.4.9", + "next": "15.4.10", "payload": "3.63.0", "react": "19.2.1", "react-dom": "19.2.1", diff --git a/templates/with-vercel-mongodb/package.json b/templates/with-vercel-mongodb/package.json index 9014b974171..d5077177e26 100644 --- a/templates/with-vercel-mongodb/package.json +++ b/templates/with-vercel-mongodb/package.json @@ -25,7 +25,7 @@ "@payloadcms/ui": "3.63.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "15.4.9", + "next": "15.4.10", "payload": "3.63.0", "react": "19.2.1", "react-dom": "19.2.1" diff --git a/templates/with-vercel-postgres/package.json b/templates/with-vercel-postgres/package.json index 58dc84b63e5..12289222c2c 100644 --- a/templates/with-vercel-postgres/package.json +++ b/templates/with-vercel-postgres/package.json @@ -26,7 +26,7 @@ "@payloadcms/ui": "3.63.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", - "next": "15.4.9", + "next": "15.4.10", "payload": "3.63.0", "react": "19.2.1", "react-dom": "19.2.1" diff --git a/templates/with-vercel-website/package.json b/templates/with-vercel-website/package.json index 26db6716c9b..e2343ae1945 100644 --- a/templates/with-vercel-website/package.json +++ b/templates/with-vercel-website/package.json @@ -46,7 +46,7 @@ "geist": "^1.3.0", "graphql": "^16.8.2", "lucide-react": "^0.378.0", - "next": "15.4.9", + "next": "15.4.10", "next-sitemap": "^4.2.3", "payload": "3.63.0", "prism-react-renderer": "^2.3.1", diff --git a/test/package.json b/test/package.json index 468c846ce3e..6f71156586d 100644 --- a/test/package.json +++ b/test/package.json @@ -94,7 +94,7 @@ "jest": "29.7.0", "jwt-decode": "4.0.0", "mongoose": "8.15.1", - "next": "15.4.9", + "next": "15.4.10", "nodemailer": "7.0.9", "object-to-formdata": "4.5.1", "payload": "workspace:*", diff --git a/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md b/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md index a678970724b..105a481a8aa 100644 --- a/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md +++ b/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md @@ -149,7 +149,7 @@ plugin-/ "copyfiles": "^2.4.1", "cross-env": "^7.0.3", "eslint": "^9.0.0", - "next": "^15.4.9", + "next": "^15.4.10", "payload": "^3.0.0", "react": "^19.2.1", "react-dom": "^19.2.1", From 88462087b1f6aa4c4ba334b97e8a691456aeb3e3 Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Sun, 14 Dec 2025 15:01:17 -0500 Subject: [PATCH 11/67] chore(release): v3.68.4 [skip ci] --- package.json | 2 +- packages/admin-bar/package.json | 2 +- packages/create-payload-app/package.json | 2 +- packages/db-d1-sqlite/package.json | 2 +- packages/db-mongodb/package.json | 2 +- packages/db-postgres/package.json | 2 +- packages/db-sqlite/package.json | 2 +- packages/db-vercel-postgres/package.json | 2 +- packages/drizzle/package.json | 2 +- packages/email-nodemailer/package.json | 2 +- packages/email-resend/package.json | 2 +- packages/graphql/package.json | 2 +- packages/kv-redis/package.json | 2 +- packages/live-preview-react/package.json | 2 +- packages/live-preview-vue/package.json | 2 +- packages/live-preview/package.json | 2 +- packages/next/package.json | 2 +- packages/payload-cloud/package.json | 2 +- packages/payload/package.json | 2 +- packages/plugin-cloud-storage/package.json | 2 +- packages/plugin-ecommerce/package.json | 2 +- packages/plugin-form-builder/package.json | 2 +- packages/plugin-import-export/package.json | 2 +- packages/plugin-mcp/package.json | 2 +- packages/plugin-multi-tenant/package.json | 2 +- packages/plugin-nested-docs/package.json | 2 +- packages/plugin-redirects/package.json | 2 +- packages/plugin-search/package.json | 2 +- packages/plugin-sentry/package.json | 2 +- packages/plugin-seo/package.json | 2 +- packages/plugin-stripe/package.json | 2 +- packages/richtext-lexical/package.json | 2 +- packages/richtext-slate/package.json | 2 +- packages/sdk/package.json | 2 +- packages/storage-azure/package.json | 2 +- packages/storage-gcs/package.json | 2 +- packages/storage-r2/package.json | 2 +- packages/storage-s3/package.json | 2 +- packages/storage-uploadthing/package.json | 2 +- packages/storage-vercel-blob/package.json | 2 +- packages/translations/package.json | 2 +- packages/ui/package.json | 2 +- 42 files changed, 42 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 28f0b745430..43e826cb594 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload-monorepo", - "version": "3.68.3", + "version": "3.68.4", "private": true, "type": "module", "workspaces": [ diff --git a/packages/admin-bar/package.json b/packages/admin-bar/package.json index 14d4443aa2f..64ba407cfbe 100644 --- a/packages/admin-bar/package.json +++ b/packages/admin-bar/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/admin-bar", - "version": "3.68.3", + "version": "3.68.4", "description": "An admin bar for React apps using Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/create-payload-app/package.json b/packages/create-payload-app/package.json index 3873c810d89..9167ea68797 100644 --- a/packages/create-payload-app/package.json +++ b/packages/create-payload-app/package.json @@ -1,6 +1,6 @@ { "name": "create-payload-app", - "version": "3.68.3", + "version": "3.68.4", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/db-d1-sqlite/package.json b/packages/db-d1-sqlite/package.json index 3dabde099ae..30e134de1f9 100644 --- a/packages/db-d1-sqlite/package.json +++ b/packages/db-d1-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-d1-sqlite", - "version": "3.68.3", + "version": "3.68.4", "description": "The officially supported D1 SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-mongodb/package.json b/packages/db-mongodb/package.json index a3094f2b137..a74e7c8e8ba 100644 --- a/packages/db-mongodb/package.json +++ b/packages/db-mongodb/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-mongodb", - "version": "3.68.3", + "version": "3.68.4", "description": "The officially supported MongoDB database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-postgres/package.json b/packages/db-postgres/package.json index da62f416374..ef3c81b158f 100644 --- a/packages/db-postgres/package.json +++ b/packages/db-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-postgres", - "version": "3.68.3", + "version": "3.68.4", "description": "The officially supported Postgres database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-sqlite/package.json b/packages/db-sqlite/package.json index 0ca92937acb..efcfe134e54 100644 --- a/packages/db-sqlite/package.json +++ b/packages/db-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-sqlite", - "version": "3.68.3", + "version": "3.68.4", "description": "The officially supported SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-vercel-postgres/package.json b/packages/db-vercel-postgres/package.json index de8c01c555d..6551018785c 100644 --- a/packages/db-vercel-postgres/package.json +++ b/packages/db-vercel-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-vercel-postgres", - "version": "3.68.3", + "version": "3.68.4", "description": "Vercel Postgres adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/drizzle/package.json b/packages/drizzle/package.json index 4a92d2789d6..083c0114173 100644 --- a/packages/drizzle/package.json +++ b/packages/drizzle/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/drizzle", - "version": "3.68.3", + "version": "3.68.4", "description": "A library of shared functions used by different payload database adapters", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-nodemailer/package.json b/packages/email-nodemailer/package.json index 3fc82426739..bba67b41d85 100644 --- a/packages/email-nodemailer/package.json +++ b/packages/email-nodemailer/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-nodemailer", - "version": "3.68.3", + "version": "3.68.4", "description": "Payload Nodemailer Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-resend/package.json b/packages/email-resend/package.json index 0c89d6a2603..4f5e9aaa628 100644 --- a/packages/email-resend/package.json +++ b/packages/email-resend/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-resend", - "version": "3.68.3", + "version": "3.68.4", "description": "Payload Resend Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/graphql/package.json b/packages/graphql/package.json index 39048d1f1fa..e65128e2c83 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/graphql", - "version": "3.68.3", + "version": "3.68.4", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/kv-redis/package.json b/packages/kv-redis/package.json index fd46bec3ccd..9be4f49f257 100644 --- a/packages/kv-redis/package.json +++ b/packages/kv-redis/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/kv-redis", - "version": "3.68.3", + "version": "3.68.4", "description": "Redis KV adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-react/package.json b/packages/live-preview-react/package.json index 6e7e5c6c8d1..bed72d95c20 100644 --- a/packages/live-preview-react/package.json +++ b/packages/live-preview-react/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-react", - "version": "3.68.3", + "version": "3.68.4", "description": "The official React SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-vue/package.json b/packages/live-preview-vue/package.json index b39ab370001..1100a62e738 100644 --- a/packages/live-preview-vue/package.json +++ b/packages/live-preview-vue/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-vue", - "version": "3.68.3", + "version": "3.68.4", "description": "The official Vue SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview/package.json b/packages/live-preview/package.json index 622ea183c54..eaec4d7fa7c 100644 --- a/packages/live-preview/package.json +++ b/packages/live-preview/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview", - "version": "3.68.3", + "version": "3.68.4", "description": "The official live preview JavaScript SDK for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/next/package.json b/packages/next/package.json index 832da42f99f..3c71808ebfe 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/next", - "version": "3.68.3", + "version": "3.68.4", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index 1fcf0d97426..48aa961dce1 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/payload-cloud", - "version": "3.68.3", + "version": "3.68.4", "description": "The official Payload Cloud plugin", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/payload/package.json b/packages/payload/package.json index 6b8a58c5e8c..5d0d3a176e4 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "3.68.3", + "version": "3.68.4", "description": "Node, React, Headless CMS and Application Framework built on Next.js", "keywords": [ "admin panel", diff --git a/packages/plugin-cloud-storage/package.json b/packages/plugin-cloud-storage/package.json index fd2513ff776..9c994732228 100644 --- a/packages/plugin-cloud-storage/package.json +++ b/packages/plugin-cloud-storage/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-cloud-storage", - "version": "3.68.3", + "version": "3.68.4", "description": "The official cloud storage plugin for Payload CMS", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-ecommerce/package.json b/packages/plugin-ecommerce/package.json index c1ac02b0dab..63390008010 100644 --- a/packages/plugin-ecommerce/package.json +++ b/packages/plugin-ecommerce/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-ecommerce", - "version": "3.68.3", + "version": "3.68.4", "description": "Ecommerce plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-form-builder/package.json b/packages/plugin-form-builder/package.json index 7719bde98e3..04d48097da9 100644 --- a/packages/plugin-form-builder/package.json +++ b/packages/plugin-form-builder/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-form-builder", - "version": "3.68.3", + "version": "3.68.4", "description": "Form builder plugin for Payload CMS", "keywords": [ "payload", diff --git a/packages/plugin-import-export/package.json b/packages/plugin-import-export/package.json index ed2be7e62fb..e1d69e75198 100644 --- a/packages/plugin-import-export/package.json +++ b/packages/plugin-import-export/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-import-export", - "version": "3.68.3", + "version": "3.68.4", "description": "Import-Export plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-mcp/package.json b/packages/plugin-mcp/package.json index dae9e34ec50..022bb92e7f6 100644 --- a/packages/plugin-mcp/package.json +++ b/packages/plugin-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-mcp", - "version": "3.68.3", + "version": "3.68.4", "description": "MCP (Model Context Protocol) capabilities with Payload", "keywords": [ "plugin", diff --git a/packages/plugin-multi-tenant/package.json b/packages/plugin-multi-tenant/package.json index 46744390077..a630b4ff3b3 100644 --- a/packages/plugin-multi-tenant/package.json +++ b/packages/plugin-multi-tenant/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-multi-tenant", - "version": "3.68.3", + "version": "3.68.4", "description": "Multi Tenant plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-nested-docs/package.json b/packages/plugin-nested-docs/package.json index bb01d38fc2e..672ef9d826c 100644 --- a/packages/plugin-nested-docs/package.json +++ b/packages/plugin-nested-docs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-nested-docs", - "version": "3.68.3", + "version": "3.68.4", "description": "The official Nested Docs plugin for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-redirects/package.json b/packages/plugin-redirects/package.json index 45f8d5de607..36862b4b31f 100644 --- a/packages/plugin-redirects/package.json +++ b/packages/plugin-redirects/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-redirects", - "version": "3.68.3", + "version": "3.68.4", "description": "Redirects plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-search/package.json b/packages/plugin-search/package.json index f08f5ca9947..0c715011443 100644 --- a/packages/plugin-search/package.json +++ b/packages/plugin-search/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-search", - "version": "3.68.3", + "version": "3.68.4", "description": "Search plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-sentry/package.json b/packages/plugin-sentry/package.json index ed05a3694f4..4b01bcf1522 100644 --- a/packages/plugin-sentry/package.json +++ b/packages/plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-sentry", - "version": "3.68.3", + "version": "3.68.4", "description": "Sentry plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-seo/package.json b/packages/plugin-seo/package.json index 40aba59186d..a199ded0bbb 100644 --- a/packages/plugin-seo/package.json +++ b/packages/plugin-seo/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-seo", - "version": "3.68.3", + "version": "3.68.4", "description": "SEO plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-stripe/package.json b/packages/plugin-stripe/package.json index 9f09d905a86..7e54407c62b 100644 --- a/packages/plugin-stripe/package.json +++ b/packages/plugin-stripe/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-stripe", - "version": "3.68.3", + "version": "3.68.4", "description": "Stripe plugin for Payload", "keywords": [ "payload", diff --git a/packages/richtext-lexical/package.json b/packages/richtext-lexical/package.json index 021647c04bc..5a8eef1181f 100644 --- a/packages/richtext-lexical/package.json +++ b/packages/richtext-lexical/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-lexical", - "version": "3.68.3", + "version": "3.68.4", "description": "The officially supported Lexical richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/richtext-slate/package.json b/packages/richtext-slate/package.json index bbf592757fa..440e3478ac4 100644 --- a/packages/richtext-slate/package.json +++ b/packages/richtext-slate/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-slate", - "version": "3.68.3", + "version": "3.68.4", "description": "The officially supported Slate richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index aa5e74681b3..84c9e541693 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/sdk", - "version": "3.68.3", + "version": "3.68.4", "description": "The official Payload REST API SDK", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-azure/package.json b/packages/storage-azure/package.json index 146e4b7ce99..2660b4e1a2e 100644 --- a/packages/storage-azure/package.json +++ b/packages/storage-azure/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-azure", - "version": "3.68.3", + "version": "3.68.4", "description": "Payload storage adapter for Azure Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-gcs/package.json b/packages/storage-gcs/package.json index b9bf835b7ee..c8b186d0f9c 100644 --- a/packages/storage-gcs/package.json +++ b/packages/storage-gcs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-gcs", - "version": "3.68.3", + "version": "3.68.4", "description": "Payload storage adapter for Google Cloud Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-r2/package.json b/packages/storage-r2/package.json index b8370abf6de..44a7cf11f7f 100644 --- a/packages/storage-r2/package.json +++ b/packages/storage-r2/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-r2", - "version": "3.68.3", + "version": "3.68.4", "description": "Payload storage adapter for Cloudflare R2", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-s3/package.json b/packages/storage-s3/package.json index b0b41275f5a..9f12d7fd638 100644 --- a/packages/storage-s3/package.json +++ b/packages/storage-s3/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-s3", - "version": "3.68.3", + "version": "3.68.4", "description": "Payload storage adapter for Amazon S3", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-uploadthing/package.json b/packages/storage-uploadthing/package.json index 95f6a3fcc60..c5274b5fcfd 100644 --- a/packages/storage-uploadthing/package.json +++ b/packages/storage-uploadthing/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-uploadthing", - "version": "3.68.3", + "version": "3.68.4", "description": "Payload storage adapter for uploadthing", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-vercel-blob/package.json b/packages/storage-vercel-blob/package.json index 8d032e80cc0..49cc280e6e3 100644 --- a/packages/storage-vercel-blob/package.json +++ b/packages/storage-vercel-blob/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-vercel-blob", - "version": "3.68.3", + "version": "3.68.4", "description": "Payload storage adapter for Vercel Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/translations/package.json b/packages/translations/package.json index 38b9a100140..8c3bc3e9dc1 100644 --- a/packages/translations/package.json +++ b/packages/translations/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/translations", - "version": "3.68.3", + "version": "3.68.4", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/ui/package.json b/packages/ui/package.json index c77dfefc5aa..3014143f61f 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/ui", - "version": "3.68.3", + "version": "3.68.4", "homepage": "https://payloadcms.com", "repository": { "type": "git", From 043bfa500a5c689c4e7574a1dfcdc13a1d848ac5 Mon Sep 17 00:00:00 2001 From: Jake Date: Mon, 15 Dec 2025 10:15:07 -0500 Subject: [PATCH 12/67] fix(next): omit server url from route matching (#14919) Follow up to https://github.com/payloadcms/payload/pull/14907. Fixes https://github.com/payloadcms/payload/issues/14900. Since https://github.com/payloadcms/payload/pull/14869, setting a `serverURL` causes some additional admin routing to break, including `/admin/logout`. We need to ensure that all routes are relative before matching them. --------- Co-authored-by: Jarrod Flesch --- packages/next/src/views/Root/getRouteData.ts | 2 +- packages/next/src/views/Root/index.tsx | 15 ++++----------- .../next/src/views/Root/isPathMatchingRoute.ts | 1 + test/helpers/e2e/auth/logout.ts | 13 +++++++++++++ test/helpers/e2e/toggleNav.ts | 15 ++++++++++++--- test/server-url/config.ts | 1 + test/server-url/e2e.spec.ts | 14 ++++++++++++-- 7 files changed, 44 insertions(+), 17 deletions(-) diff --git a/packages/next/src/views/Root/getRouteData.ts b/packages/next/src/views/Root/getRouteData.ts index f685d4723f3..8f0205fbabd 100644 --- a/packages/next/src/views/Root/getRouteData.ts +++ b/packages/next/src/views/Root/getRouteData.ts @@ -160,7 +160,7 @@ export const getRouteData = ({ return isPathMatchingRoute({ currentRoute, exact: true, - path: formatAdminURL({ adminRoute, path: route, serverURL: config.serverURL }), + path: formatAdminURL({ adminRoute, path: route }), }) }) diff --git a/packages/next/src/views/Root/index.tsx b/packages/next/src/views/Root/index.tsx index a00bef04870..d6656b44abd 100644 --- a/packages/next/src/views/Root/index.tsx +++ b/packages/next/src/views/Root/index.tsx @@ -63,10 +63,10 @@ export const RootPage = async ({ const params = await paramsPromise + // Intentionally omit `serverURL` to ensure relative path const currentRoute = formatAdminURL({ adminRoute, path: Array.isArray(params.segments) ? `/${params.segments.join('/')}` : null, - serverURL: config.serverURL, }) const segments = Array.isArray(params.segments) ? params.segments : [] @@ -140,10 +140,7 @@ export const RootPage = async ({ }), }, // intentionally omit `serverURL` to keep URL relative - urlSuffix: `${formatAdminURL({ - adminRoute, - path: Array.isArray(params.segments) ? `/${params.segments.join('/')}` : null, - })}${searchParams ? queryString : ''}`, + urlSuffix: `${currentRoute}${searchParams ? queryString : ''}`, }, }) @@ -224,15 +221,11 @@ export const RootPage = async ({ } } - const createFirstUserRoute = formatAdminURL({ - adminRoute, - path: _createFirstUserRoute, - serverURL: config.serverURL, - }) - const usersCollection = config.collections.find(({ slug }) => slug === userSlug) const disableLocalStrategy = usersCollection?.auth?.disableLocalStrategy + const createFirstUserRoute = formatAdminURL({ adminRoute, path: _createFirstUserRoute }) + if (disableLocalStrategy && currentRoute === createFirstUserRoute) { redirect(adminRoute) } diff --git a/packages/next/src/views/Root/isPathMatchingRoute.ts b/packages/next/src/views/Root/isPathMatchingRoute.ts index 0ef4fbf9ff8..193fc0042a8 100644 --- a/packages/next/src/views/Root/isPathMatchingRoute.ts +++ b/packages/next/src/views/Root/isPathMatchingRoute.ts @@ -33,6 +33,7 @@ export const isPathMatchingRoute = ({ if (exact) { return currentRoute === viewRoute } + if (!exact) { return viewRoute.startsWith(currentRoute) } diff --git a/test/helpers/e2e/auth/logout.ts b/test/helpers/e2e/auth/logout.ts index b35da897a0c..0b87fee7764 100644 --- a/test/helpers/e2e/auth/logout.ts +++ b/test/helpers/e2e/auth/logout.ts @@ -3,6 +3,8 @@ import type { Page } from 'playwright' import { POLL_TOPASS_TIMEOUT } from 'playwright.config.js' import { expect } from 'playwright/test' +import { openNav } from '../toggleNav.js' + export const logout = async (page: Page, serverURL: string) => { await page.goto(`${serverURL}/admin/logout`) @@ -10,3 +12,14 @@ export const logout = async (page: Page, serverURL: string) => { await expect(page.locator('.login')).toBeVisible() } + +export const logoutViaNav = async (page: Page) => { + const { nav } = await openNav(page) + const logoutAnchor = nav.locator('a[title="Log out"]') + await expect(logoutAnchor).toBeVisible() + await logoutAnchor.click() + + await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).toContain('/admin/login') + + await expect(page.locator('.login')).toBeVisible() +} diff --git a/test/helpers/e2e/toggleNav.ts b/test/helpers/e2e/toggleNav.ts index 6f7ad8464bb..dafd328dd6b 100644 --- a/test/helpers/e2e/toggleNav.ts +++ b/test/helpers/e2e/toggleNav.ts @@ -2,12 +2,13 @@ import type { Page } from '@playwright/test' import { expect } from '@playwright/test' -export async function openNav(page: Page): Promise { +export async function openNav(page: Page): Promise<{ nav: ReturnType }> { // wait for the preferences/media queries to either open or close the nav await expect(page.locator('.template-default--nav-hydrated')).toBeVisible() // close all open modals const dialogs = await page.locator('dialog[open]').elementHandles() + for (let i = 0; i < dialogs.length; i++) { await page.keyboard.press('Escape') } @@ -15,14 +16,22 @@ export async function openNav(page: Page): Promise { // check to see if the nav is already open and if not, open it // use the `--nav-open` modifier class to check if the nav is open // this will prevent clicking nav links that are bleeding off the screen - if (await page.locator('.template-default.template-default--nav-open').isVisible()) { - return + const nav = page.locator('.template-default.template-default--nav-open') + + if (await nav.isVisible()) { + return { + nav, + } } // playwright: get first element with .nav-toggler which is VISIBLE (not hidden), could be 2 elements with .nav-toggler on mobile and desktop but only one is visible await page.locator('.nav-toggler >> visible=true').click() await expect(page.locator('.nav--nav-animate[inert], .nav--nav-hydrated[inert]')).toBeHidden() await expect(page.locator('.template-default.template-default--nav-open')).toBeVisible() + + return { + nav, + } } export async function closeNav(page: Page): Promise { diff --git a/test/server-url/config.ts b/test/server-url/config.ts index e0903b91343..03c5a2f90a6 100644 --- a/test/server-url/config.ts +++ b/test/server-url/config.ts @@ -11,6 +11,7 @@ const dirname = path.dirname(filename) export default buildConfigWithDefaults({ serverURL: 'http://localhost:3000', admin: { + autoLogin: false, importMap: { baseDir: path.resolve(dirname), }, diff --git a/test/server-url/e2e.spec.ts b/test/server-url/e2e.spec.ts index 19d8be8b9a2..f576bbb223a 100644 --- a/test/server-url/e2e.spec.ts +++ b/test/server-url/e2e.spec.ts @@ -1,6 +1,9 @@ import type { Page } from '@playwright/test' import { expect, test } from '@playwright/test' +import { login } from 'helpers/e2e/auth/login.js' +import { logoutViaNav } from 'helpers/e2e/auth/logout.js' +import { openNav } from 'helpers/e2e/toggleNav.js' import * as path from 'path' import { fileURLToPath } from 'url' @@ -28,8 +31,15 @@ test.describe('serverURL', () => { await ensureCompilationIsDone({ page, serverURL }) }) - test('can load admin panel when serverURL is set', async () => { + test('can load admin panel', async () => { + await login({ page, serverURL: url.serverURL }) await page.goto(url.admin) - await expect(page.getByText('Dashboard')).toBeVisible() + await expect(page.locator('.dashboard')).toBeVisible() + }) + + test('can log out', async () => { + await page.goto(url.admin) + await logoutViaNav(page) + await expect(page.locator('.login')).toBeVisible() }) }) From 9bb1e43d02615390fcb910c6038859b0a3b9d6ed Mon Sep 17 00:00:00 2001 From: Jake Date: Mon, 15 Dec 2025 15:02:29 -0500 Subject: [PATCH 13/67] refactor: add relative flag to formatAdminURL util (#14925) Adds a `relative` flag to the `formatAdminURL` util. There are cases where this function can produce a fully qualified URL, like for client-side routing, and other times when it must remain relative, like when matching routes. This flag differentiates these two behaviors declaratively so we don't have to rely on the omission of `serverURL`. ```ts const result = formatAdminURL({ adminRoute: '/admin', basePath: '/v1', path: '/collections/posts', serverURL: 'http://payloadcms.com', relative: true, }) // returns '/v1/admin/collections/posts' ``` Related: https://github.com/payloadcms/payload/pull/14919 and https://github.com/payloadcms/payload/pull/14907 --- packages/next/src/views/Root/getRouteData.ts | 7 +- packages/next/src/views/Root/index.tsx | 9 +- .../src/utilities/formatAdminURL.spec.ts | 206 ++++++++++++++++++ .../payload/src/utilities/formatAdminURL.ts | 58 +++-- 4 files changed, 260 insertions(+), 20 deletions(-) create mode 100644 packages/payload/src/utilities/formatAdminURL.spec.ts diff --git a/packages/next/src/views/Root/getRouteData.ts b/packages/next/src/views/Root/getRouteData.ts index 8f0205fbabd..77be06d89e8 100644 --- a/packages/next/src/views/Root/getRouteData.ts +++ b/packages/next/src/views/Root/getRouteData.ts @@ -160,7 +160,12 @@ export const getRouteData = ({ return isPathMatchingRoute({ currentRoute, exact: true, - path: formatAdminURL({ adminRoute, path: route }), + path: formatAdminURL({ + adminRoute, + path: route, + relative: true, + serverURL: config.serverURL, + }), }) }) diff --git a/packages/next/src/views/Root/index.tsx b/packages/next/src/views/Root/index.tsx index d6656b44abd..e43278a4f86 100644 --- a/packages/next/src/views/Root/index.tsx +++ b/packages/next/src/views/Root/index.tsx @@ -67,6 +67,8 @@ export const RootPage = async ({ const currentRoute = formatAdminURL({ adminRoute, path: Array.isArray(params.segments) ? `/${params.segments.join('/')}` : null, + relative: true, + serverURL: config.serverURL, }) const segments = Array.isArray(params.segments) ? params.segments : [] @@ -224,7 +226,12 @@ export const RootPage = async ({ const usersCollection = config.collections.find(({ slug }) => slug === userSlug) const disableLocalStrategy = usersCollection?.auth?.disableLocalStrategy - const createFirstUserRoute = formatAdminURL({ adminRoute, path: _createFirstUserRoute }) + const createFirstUserRoute = formatAdminURL({ + adminRoute, + path: _createFirstUserRoute, + relative: true, + serverURL: config.serverURL, + }) if (disableLocalStrategy && currentRoute === createFirstUserRoute) { redirect(adminRoute) diff --git a/packages/payload/src/utilities/formatAdminURL.spec.ts b/packages/payload/src/utilities/formatAdminURL.spec.ts new file mode 100644 index 00000000000..8e592239fc8 --- /dev/null +++ b/packages/payload/src/utilities/formatAdminURL.spec.ts @@ -0,0 +1,206 @@ +import { formatAdminURL } from './formatAdminURL.js' + +describe('formatAdminURL', () => { + const serverURL = 'https://example.com' + + const defaultAdminRoute = '/admin' + const rootAdminRoute = '/' + + const dummyPath = '/collections/posts' + + describe('relative URLs', () => { + it('should ignore `serverURL` when relative=true', () => { + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + path: dummyPath, + serverURL, + relative: true, + }) + + expect(result).toBe(`${defaultAdminRoute}${dummyPath}`) + }) + + it('should force relative URL when `serverURL` is omitted', () => { + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + path: dummyPath, + relative: false, + }) + + expect(result).toBe(`${defaultAdminRoute}${dummyPath}`) + }) + }) + + describe('absolute URLs', () => { + it('should return absolute URL with serverURL', () => { + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + path: dummyPath, + serverURL, + }) + + expect(result).toBe(`${serverURL}${defaultAdminRoute}${dummyPath}`) + }) + + it('should handle serverURL with trailing slash', () => { + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + path: '/collections/posts', + serverURL: 'https://example.com/', + }) + + expect(result).toBe('https://example.com/admin/collections/posts') + }) + + it('should handle serverURL with subdirectory', () => { + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + path: '/collections/posts', + serverURL: 'https://example.com/api/v1', + }) + + expect(result).toBe('https://example.com/admin/collections/posts') + }) + }) + + describe('admin route handling', () => { + it('should return relative URL for adminRoute="/", no path, no `serverURL`', () => { + const result = formatAdminURL({ + adminRoute: rootAdminRoute, + relative: true, + }) + + expect(result).toBe('/') + }) + + it('should handle relative URL for adminRoute="/", with path, no `serverURL`', () => { + const result = formatAdminURL({ + adminRoute: rootAdminRoute, + path: dummyPath, + relative: true, + }) + + expect(result).toBe(dummyPath) + }) + + it('should return absolute URL for adminRoute="/", no path, with `serverURL`', () => { + const result = formatAdminURL({ + adminRoute: rootAdminRoute, + serverURL, + }) + + expect(result).toBe('https://example.com/') + }) + + it('should handle absolute URL for adminRoute="/", with path and `serverURL`', () => { + const result = formatAdminURL({ + adminRoute: rootAdminRoute, + serverURL, + path: dummyPath, + }) + + expect(result).toBe(`${serverURL}${dummyPath}`) + }) + }) + + describe('base path handling', () => { + it('should include basePath in URL', () => { + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + basePath: '/v1', + path: dummyPath, + serverURL, + }) + + expect(result).toBe(`${serverURL}/v1${defaultAdminRoute}${dummyPath}`) + }) + + it('should handle basePath with adminRoute="/"', () => { + const result = formatAdminURL({ + adminRoute: rootAdminRoute, + basePath: '/v1', + serverURL, + }) + + expect(result).toBe(`${serverURL}/v1`) + }) + + it('should handle basePath with no adminRoute', () => { + const result = formatAdminURL({ + adminRoute: undefined, + basePath: '/v1', + path: dummyPath, + serverURL, + }) + + expect(result).toBe(`${serverURL}/v1${dummyPath}`) + }) + + it('should handle empty basePath', () => { + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + basePath: '', + path: dummyPath, + serverURL, + }) + + expect(result).toBe(`${serverURL}${defaultAdminRoute}${dummyPath}`) + }) + }) + + describe('path handling', () => { + it('should handle empty string path', () => { + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + path: '', + serverURL, + }) + + expect(result).toBe(`${serverURL}${defaultAdminRoute}`) + }) + + it('should handle null path', () => { + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + path: null, + serverURL, + }) + expect(result).toBe(`${serverURL}${defaultAdminRoute}`) + }) + + it('should handle undefined path', () => { + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + path: undefined, + serverURL, + }) + + expect(result).toBe(`${serverURL}${defaultAdminRoute}`) + }) + + it('should handle path with query parameters', () => { + const path = `${dummyPath}?page=2` + + const result = formatAdminURL({ + adminRoute: defaultAdminRoute, + path, + serverURL, + }) + + expect(result).toBe(`${serverURL}${defaultAdminRoute}${path}`) + }) + }) + + describe('edge cases', () => { + it('should return "/" when given minimal args', () => { + const result = formatAdminURL({ + adminRoute: undefined, + basePath: '', + path: '', + relative: true, + }) + + expect(result).toBe('/') + }) + }) +}) diff --git a/packages/payload/src/utilities/formatAdminURL.ts b/packages/payload/src/utilities/formatAdminURL.ts index 2ba612838ed..0becb74b1c4 100644 --- a/packages/payload/src/utilities/formatAdminURL.ts +++ b/packages/payload/src/utilities/formatAdminURL.ts @@ -1,24 +1,46 @@ import type { Config } from '../config/types.js' -/** Will read the `routes.admin` config and appropriately handle `"/"` admin paths */ -export const formatAdminURL = (args: { - adminRoute: NonNullable['admin'] - basePath?: string - path: '' | `/${string}` | null | undefined - serverURL?: Config['serverURL'] -}): string => { - const { adminRoute, basePath = '', path: pathFromArgs, serverURL } = args - const path = pathFromArgs || '' +/** + * This function builds correct URLs for admin panel routing. + * Its primary responsibilities are: + * 1. Read from your `routes.admin` config and appropriately handle `"/"` admin paths + * 2. Prepend the `basePath` from your Next.js config, if specified + * 3. Return relative or absolute URLs, as needed + */ +export const formatAdminURL = ( + args: { + adminRoute: NonNullable['admin'] + /** + * The subpath of your application, if specified. + * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/basePath + * @example '/docs' + */ + basePath?: string + path?: '' | `/${string}` | null + /** + * Return a relative URL, e.g. ignore `serverURL`. + * Useful for route-matching, etc. + */ + relative?: boolean + } & Pick, +): string => { + const { adminRoute, basePath = '', path = '', relative = false, serverURL } = args - if (adminRoute) { - if (adminRoute === '/') { - if (!path) { - return `${serverURL || ''}${basePath}${adminRoute}` - } - } else { - return `${serverURL || ''}${basePath}${adminRoute}${path}` - } + const pathSegments = [basePath] + + if (adminRoute && adminRoute !== '/') { + pathSegments.push(adminRoute) + } + + if (path && !(adminRoute === '/' && !path)) { + pathSegments.push(path) + } + + const pathname = pathSegments.join('') || '/' + + if (relative || !serverURL) { + return pathname } - return `${serverURL || ''}${basePath}${path}` + return new URL(pathname, serverURL).toString() } From 723f9d4bea66c4881bf77513d3f90f22059e5eaa Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Mon, 15 Dec 2025 15:06:27 -0500 Subject: [PATCH 14/67] chore(release): v3.68.5 [skip ci] --- package.json | 2 +- packages/admin-bar/package.json | 2 +- packages/create-payload-app/package.json | 2 +- packages/db-d1-sqlite/package.json | 2 +- packages/db-mongodb/package.json | 2 +- packages/db-postgres/package.json | 2 +- packages/db-sqlite/package.json | 2 +- packages/db-vercel-postgres/package.json | 2 +- packages/drizzle/package.json | 2 +- packages/email-nodemailer/package.json | 2 +- packages/email-resend/package.json | 2 +- packages/graphql/package.json | 2 +- packages/kv-redis/package.json | 2 +- packages/live-preview-react/package.json | 2 +- packages/live-preview-vue/package.json | 2 +- packages/live-preview/package.json | 2 +- packages/next/package.json | 2 +- packages/payload-cloud/package.json | 2 +- packages/payload/package.json | 2 +- packages/plugin-cloud-storage/package.json | 2 +- packages/plugin-ecommerce/package.json | 2 +- packages/plugin-form-builder/package.json | 2 +- packages/plugin-import-export/package.json | 2 +- packages/plugin-mcp/package.json | 2 +- packages/plugin-multi-tenant/package.json | 2 +- packages/plugin-nested-docs/package.json | 2 +- packages/plugin-redirects/package.json | 2 +- packages/plugin-search/package.json | 2 +- packages/plugin-sentry/package.json | 2 +- packages/plugin-seo/package.json | 2 +- packages/plugin-stripe/package.json | 2 +- packages/richtext-lexical/package.json | 2 +- packages/richtext-slate/package.json | 2 +- packages/sdk/package.json | 2 +- packages/storage-azure/package.json | 2 +- packages/storage-gcs/package.json | 2 +- packages/storage-r2/package.json | 2 +- packages/storage-s3/package.json | 2 +- packages/storage-uploadthing/package.json | 2 +- packages/storage-vercel-blob/package.json | 2 +- packages/translations/package.json | 2 +- packages/ui/package.json | 2 +- 42 files changed, 42 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 43e826cb594..03b1dc879e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload-monorepo", - "version": "3.68.4", + "version": "3.68.5", "private": true, "type": "module", "workspaces": [ diff --git a/packages/admin-bar/package.json b/packages/admin-bar/package.json index 64ba407cfbe..854efc64a31 100644 --- a/packages/admin-bar/package.json +++ b/packages/admin-bar/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/admin-bar", - "version": "3.68.4", + "version": "3.68.5", "description": "An admin bar for React apps using Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/create-payload-app/package.json b/packages/create-payload-app/package.json index 9167ea68797..c15d31f048e 100644 --- a/packages/create-payload-app/package.json +++ b/packages/create-payload-app/package.json @@ -1,6 +1,6 @@ { "name": "create-payload-app", - "version": "3.68.4", + "version": "3.68.5", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/db-d1-sqlite/package.json b/packages/db-d1-sqlite/package.json index 30e134de1f9..d2a103ab0ab 100644 --- a/packages/db-d1-sqlite/package.json +++ b/packages/db-d1-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-d1-sqlite", - "version": "3.68.4", + "version": "3.68.5", "description": "The officially supported D1 SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-mongodb/package.json b/packages/db-mongodb/package.json index a74e7c8e8ba..c8447cec23f 100644 --- a/packages/db-mongodb/package.json +++ b/packages/db-mongodb/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-mongodb", - "version": "3.68.4", + "version": "3.68.5", "description": "The officially supported MongoDB database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-postgres/package.json b/packages/db-postgres/package.json index ef3c81b158f..3df472b8812 100644 --- a/packages/db-postgres/package.json +++ b/packages/db-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-postgres", - "version": "3.68.4", + "version": "3.68.5", "description": "The officially supported Postgres database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-sqlite/package.json b/packages/db-sqlite/package.json index efcfe134e54..61136bd4d19 100644 --- a/packages/db-sqlite/package.json +++ b/packages/db-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-sqlite", - "version": "3.68.4", + "version": "3.68.5", "description": "The officially supported SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-vercel-postgres/package.json b/packages/db-vercel-postgres/package.json index 6551018785c..0b7a6c84462 100644 --- a/packages/db-vercel-postgres/package.json +++ b/packages/db-vercel-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-vercel-postgres", - "version": "3.68.4", + "version": "3.68.5", "description": "Vercel Postgres adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/drizzle/package.json b/packages/drizzle/package.json index 083c0114173..349cc488e7d 100644 --- a/packages/drizzle/package.json +++ b/packages/drizzle/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/drizzle", - "version": "3.68.4", + "version": "3.68.5", "description": "A library of shared functions used by different payload database adapters", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-nodemailer/package.json b/packages/email-nodemailer/package.json index bba67b41d85..b7eb6cbbc04 100644 --- a/packages/email-nodemailer/package.json +++ b/packages/email-nodemailer/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-nodemailer", - "version": "3.68.4", + "version": "3.68.5", "description": "Payload Nodemailer Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-resend/package.json b/packages/email-resend/package.json index 4f5e9aaa628..44421ba53c6 100644 --- a/packages/email-resend/package.json +++ b/packages/email-resend/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-resend", - "version": "3.68.4", + "version": "3.68.5", "description": "Payload Resend Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/graphql/package.json b/packages/graphql/package.json index e65128e2c83..759a1c39a81 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/graphql", - "version": "3.68.4", + "version": "3.68.5", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/kv-redis/package.json b/packages/kv-redis/package.json index 9be4f49f257..d96ab21e31b 100644 --- a/packages/kv-redis/package.json +++ b/packages/kv-redis/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/kv-redis", - "version": "3.68.4", + "version": "3.68.5", "description": "Redis KV adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-react/package.json b/packages/live-preview-react/package.json index bed72d95c20..6b4f2e40c54 100644 --- a/packages/live-preview-react/package.json +++ b/packages/live-preview-react/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-react", - "version": "3.68.4", + "version": "3.68.5", "description": "The official React SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-vue/package.json b/packages/live-preview-vue/package.json index 1100a62e738..3630845e727 100644 --- a/packages/live-preview-vue/package.json +++ b/packages/live-preview-vue/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-vue", - "version": "3.68.4", + "version": "3.68.5", "description": "The official Vue SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview/package.json b/packages/live-preview/package.json index eaec4d7fa7c..92b305fcdb3 100644 --- a/packages/live-preview/package.json +++ b/packages/live-preview/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview", - "version": "3.68.4", + "version": "3.68.5", "description": "The official live preview JavaScript SDK for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/next/package.json b/packages/next/package.json index 3c71808ebfe..80d5a58e433 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/next", - "version": "3.68.4", + "version": "3.68.5", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index 48aa961dce1..aab26b294fa 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/payload-cloud", - "version": "3.68.4", + "version": "3.68.5", "description": "The official Payload Cloud plugin", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/payload/package.json b/packages/payload/package.json index 5d0d3a176e4..c1541cc19e7 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "3.68.4", + "version": "3.68.5", "description": "Node, React, Headless CMS and Application Framework built on Next.js", "keywords": [ "admin panel", diff --git a/packages/plugin-cloud-storage/package.json b/packages/plugin-cloud-storage/package.json index 9c994732228..cba90239349 100644 --- a/packages/plugin-cloud-storage/package.json +++ b/packages/plugin-cloud-storage/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-cloud-storage", - "version": "3.68.4", + "version": "3.68.5", "description": "The official cloud storage plugin for Payload CMS", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-ecommerce/package.json b/packages/plugin-ecommerce/package.json index 63390008010..1512d35e574 100644 --- a/packages/plugin-ecommerce/package.json +++ b/packages/plugin-ecommerce/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-ecommerce", - "version": "3.68.4", + "version": "3.68.5", "description": "Ecommerce plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-form-builder/package.json b/packages/plugin-form-builder/package.json index 04d48097da9..a21d0ab7b12 100644 --- a/packages/plugin-form-builder/package.json +++ b/packages/plugin-form-builder/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-form-builder", - "version": "3.68.4", + "version": "3.68.5", "description": "Form builder plugin for Payload CMS", "keywords": [ "payload", diff --git a/packages/plugin-import-export/package.json b/packages/plugin-import-export/package.json index e1d69e75198..de6a46ed83d 100644 --- a/packages/plugin-import-export/package.json +++ b/packages/plugin-import-export/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-import-export", - "version": "3.68.4", + "version": "3.68.5", "description": "Import-Export plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-mcp/package.json b/packages/plugin-mcp/package.json index 022bb92e7f6..78828d1acc4 100644 --- a/packages/plugin-mcp/package.json +++ b/packages/plugin-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-mcp", - "version": "3.68.4", + "version": "3.68.5", "description": "MCP (Model Context Protocol) capabilities with Payload", "keywords": [ "plugin", diff --git a/packages/plugin-multi-tenant/package.json b/packages/plugin-multi-tenant/package.json index a630b4ff3b3..0297f95544b 100644 --- a/packages/plugin-multi-tenant/package.json +++ b/packages/plugin-multi-tenant/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-multi-tenant", - "version": "3.68.4", + "version": "3.68.5", "description": "Multi Tenant plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-nested-docs/package.json b/packages/plugin-nested-docs/package.json index 672ef9d826c..5019b68a6ca 100644 --- a/packages/plugin-nested-docs/package.json +++ b/packages/plugin-nested-docs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-nested-docs", - "version": "3.68.4", + "version": "3.68.5", "description": "The official Nested Docs plugin for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-redirects/package.json b/packages/plugin-redirects/package.json index 36862b4b31f..06405de51d3 100644 --- a/packages/plugin-redirects/package.json +++ b/packages/plugin-redirects/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-redirects", - "version": "3.68.4", + "version": "3.68.5", "description": "Redirects plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-search/package.json b/packages/plugin-search/package.json index 0c715011443..20e92f42298 100644 --- a/packages/plugin-search/package.json +++ b/packages/plugin-search/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-search", - "version": "3.68.4", + "version": "3.68.5", "description": "Search plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-sentry/package.json b/packages/plugin-sentry/package.json index 4b01bcf1522..5296b75e1e3 100644 --- a/packages/plugin-sentry/package.json +++ b/packages/plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-sentry", - "version": "3.68.4", + "version": "3.68.5", "description": "Sentry plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-seo/package.json b/packages/plugin-seo/package.json index a199ded0bbb..36e64b41fee 100644 --- a/packages/plugin-seo/package.json +++ b/packages/plugin-seo/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-seo", - "version": "3.68.4", + "version": "3.68.5", "description": "SEO plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-stripe/package.json b/packages/plugin-stripe/package.json index 7e54407c62b..4822927a45f 100644 --- a/packages/plugin-stripe/package.json +++ b/packages/plugin-stripe/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-stripe", - "version": "3.68.4", + "version": "3.68.5", "description": "Stripe plugin for Payload", "keywords": [ "payload", diff --git a/packages/richtext-lexical/package.json b/packages/richtext-lexical/package.json index 5a8eef1181f..fc57a62575c 100644 --- a/packages/richtext-lexical/package.json +++ b/packages/richtext-lexical/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-lexical", - "version": "3.68.4", + "version": "3.68.5", "description": "The officially supported Lexical richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/richtext-slate/package.json b/packages/richtext-slate/package.json index 440e3478ac4..67d345ebf25 100644 --- a/packages/richtext-slate/package.json +++ b/packages/richtext-slate/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-slate", - "version": "3.68.4", + "version": "3.68.5", "description": "The officially supported Slate richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 84c9e541693..e8d5a2c4fb8 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/sdk", - "version": "3.68.4", + "version": "3.68.5", "description": "The official Payload REST API SDK", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-azure/package.json b/packages/storage-azure/package.json index 2660b4e1a2e..e4b18fda951 100644 --- a/packages/storage-azure/package.json +++ b/packages/storage-azure/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-azure", - "version": "3.68.4", + "version": "3.68.5", "description": "Payload storage adapter for Azure Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-gcs/package.json b/packages/storage-gcs/package.json index c8b186d0f9c..e9a538b7de2 100644 --- a/packages/storage-gcs/package.json +++ b/packages/storage-gcs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-gcs", - "version": "3.68.4", + "version": "3.68.5", "description": "Payload storage adapter for Google Cloud Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-r2/package.json b/packages/storage-r2/package.json index 44a7cf11f7f..7ac37a9330f 100644 --- a/packages/storage-r2/package.json +++ b/packages/storage-r2/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-r2", - "version": "3.68.4", + "version": "3.68.5", "description": "Payload storage adapter for Cloudflare R2", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-s3/package.json b/packages/storage-s3/package.json index 9f12d7fd638..6201cca51b7 100644 --- a/packages/storage-s3/package.json +++ b/packages/storage-s3/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-s3", - "version": "3.68.4", + "version": "3.68.5", "description": "Payload storage adapter for Amazon S3", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-uploadthing/package.json b/packages/storage-uploadthing/package.json index c5274b5fcfd..377becd094c 100644 --- a/packages/storage-uploadthing/package.json +++ b/packages/storage-uploadthing/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-uploadthing", - "version": "3.68.4", + "version": "3.68.5", "description": "Payload storage adapter for uploadthing", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-vercel-blob/package.json b/packages/storage-vercel-blob/package.json index 49cc280e6e3..62ea5a3b692 100644 --- a/packages/storage-vercel-blob/package.json +++ b/packages/storage-vercel-blob/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-vercel-blob", - "version": "3.68.4", + "version": "3.68.5", "description": "Payload storage adapter for Vercel Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/translations/package.json b/packages/translations/package.json index 8c3bc3e9dc1..1596bc2c54e 100644 --- a/packages/translations/package.json +++ b/packages/translations/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/translations", - "version": "3.68.4", + "version": "3.68.5", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/ui/package.json b/packages/ui/package.json index 3014143f61f..cd686664086 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/ui", - "version": "3.68.4", + "version": "3.68.5", "homepage": "https://payloadcms.com", "repository": { "type": "git", From 5298f0cb5f206f034f0f0dce7986e5f2fff96368 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Mon, 15 Dec 2025 12:12:47 -0800 Subject: [PATCH 15/67] fix(ui): use portals for popup to prevent clipping, improve keyboard navigation (#14910) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the Popup contents were displayed relative to the Popup trigger button. This caused the Popup contents to be hidden if the parent element has `overflow: hidden`, which was the case for doc_controls on smaller screen sizes (this PR adds an e2e test that previously failed). This PR refactors the Popup component to use `createPortal`, rendering the popup content directly to `document.body` to avoid clipping issues. ## Before https://github.com/user-attachments/assets/c1cc341a-2295-45b6-89d0-7e89866e5bfd ## After https://github.com/user-attachments/assets/2eb0d8b5-105e-468b-bd66-8ef8261a6306 While refactoring, I also improved the keyboard navigation for popups: | Feature | Before | After | |---------|--------|-------| | Tab cycling | Exited popup after last button | Cycles and goes back to first button | | Escape key | Did nothing | Closes popup and returns focus to trigger | | Arrow keys | Scrolled the page | Navigates between buttons (↑/↓) | | Button focus styling | Bad | Good | | `` elements | Skipped during navigation | Included in keyboard navigation | ## Keyboard navigation before https://github.com/user-attachments/assets/9d212c90-7759-42cf-ad37-d7ee7dc64c5d ## Keyboard navigation after https://github.com/user-attachments/assets/dbc7d647-b58b-4e5b-928c-a6f3fdab6348 --- .../ui/src/elements/ListControls/index.tsx | 10 +- .../elements/Popup/PopupButtonList/index.scss | 1 + .../src/elements/Popup/PopupTrigger/index.tsx | 27 +- packages/ui/src/elements/Popup/index.scss | 280 ++-------- packages/ui/src/elements/Popup/index.tsx | 482 +++++++++++++----- packages/ui/src/scss/app.scss | 3 +- test/admin/e2e/document-view/e2e.spec.ts | 6 +- test/admin/e2e/general/e2e.spec.ts | 24 +- test/admin/e2e/list-view/e2e.spec.ts | 14 +- test/fields/collections/Array/e2e.spec.ts | 4 +- test/fields/collections/Blocks/e2e.spec.ts | 4 +- .../collections/Relationship/e2e.spec.ts | 18 +- test/folders/e2e.spec.ts | 31 +- test/helpers.ts | 10 +- test/helpers/e2e/copyPasteField.ts | 6 +- .../e2e/fields/array/openArrayRowActions.ts | 2 +- .../selectLivePreviewBreakpoint.ts | 6 +- .../e2e/live-preview/selectLivePreviewZoom.ts | 15 +- test/helpers/e2e/openDocControls.ts | 9 +- .../folders/applyBrowseByFolderTypeFilter.ts | 4 +- test/helpers/folders/createFolder.ts | 2 +- test/joins/e2e.spec.ts | 6 +- .../collections/Lexical/e2e/main/e2e.spec.ts | 4 +- test/lexical/collections/RichText/e2e.spec.ts | 6 +- test/localization/e2e.spec.ts | 44 +- test/plugin-multi-tenant/e2e.spec.ts | 4 +- test/trash/e2e.spec.ts | 8 +- test/versions/e2e.spec.ts | 6 +- 28 files changed, 541 insertions(+), 495 deletions(-) diff --git a/packages/ui/src/elements/ListControls/index.tsx b/packages/ui/src/elements/ListControls/index.tsx index 9930dec743a..54ef38c80fc 100644 --- a/packages/ui/src/elements/ListControls/index.tsx +++ b/packages/ui/src/elements/ListControls/index.tsx @@ -7,7 +7,7 @@ import React, { Fragment, useEffect, useRef, useState } from 'react' import type { ListControlsProps } from './types.js' -import { Popup } from '../../elements/Popup/index.js' +import { Popup, PopupList } from '../../elements/Popup/index.js' import { useUseTitleField } from '../../hooks/useUseAsTitle.js' import { ChevronIcon } from '../../icons/Chevron/index.js' import { Dots } from '../../icons/Dots/index.js' @@ -210,9 +210,11 @@ export const ListControls: React.FC = (props) => { size="small" verticalAlign="bottom" > - {listMenuItems.map((item, i) => ( - {item} - ))} + + {listMenuItems.map((item, i) => ( + {item} + ))} + ), ].filter(Boolean)} diff --git a/packages/ui/src/elements/Popup/PopupButtonList/index.scss b/packages/ui/src/elements/Popup/PopupButtonList/index.scss index 5ca3035a3fa..48ae5e8915b 100644 --- a/packages/ui/src/elements/Popup/PopupButtonList/index.scss +++ b/packages/ui/src/elements/Popup/PopupButtonList/index.scss @@ -47,6 +47,7 @@ &:hover, &:focus-visible, &:focus-within { + outline: none; background-color: var(--popup-button-highlight); } } diff --git a/packages/ui/src/elements/Popup/PopupTrigger/index.tsx b/packages/ui/src/elements/Popup/PopupTrigger/index.tsx index 6bf6022eae6..7b4d605ca8f 100644 --- a/packages/ui/src/elements/Popup/PopupTrigger/index.tsx +++ b/packages/ui/src/elements/Popup/PopupTrigger/index.tsx @@ -12,7 +12,7 @@ export type PopupTriggerProps = { className?: string disabled?: boolean noBackground?: boolean - setActive: (active: boolean) => void + setActive: (active: boolean, viaKeyboard?: boolean) => void size?: 'large' | 'medium' | 'small' | 'xsmall' } @@ -30,9 +30,16 @@ export const PopupTrigger: React.FC = (props) => { .filter(Boolean) .join(' ') - const handleClick = React.useCallback(() => { - setActive(!active) - }, [active, setActive]) + const handleClick = () => { + setActive(!active, false) + } + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault() + setActive(!active, true) + } + } if (buttonType === 'none') { return null @@ -43,11 +50,7 @@ export const PopupTrigger: React.FC = (props) => {
{ - if (e.key === 'Enter') { - handleClick() - } - }} + onKeyDown={handleKeyDown} role="button" tabIndex={0} > @@ -61,11 +64,7 @@ export const PopupTrigger: React.FC = (props) => { className={classes} disabled={disabled} onClick={handleClick} - onKeyDown={(e) => { - if (e.key === 'Enter') { - handleClick() - } - }} + onKeyDown={handleKeyDown} tabIndex={0} type="button" > diff --git a/packages/ui/src/elements/Popup/index.scss b/packages/ui/src/elements/Popup/index.scss index 0d214aaab44..65034084f59 100644 --- a/packages/ui/src/elements/Popup/index.scss +++ b/packages/ui/src/elements/Popup/index.scss @@ -2,13 +2,6 @@ @layer payload-default { .popup { - --popup-button-highlight: var(--theme-elevation-200); - --popup-bg: var(--theme-input-bg); - --popup-text: var(--theme-text); - --popup-caret-size: 10px; - --popup-x-padding: calc(var(--base) * 0.33); - --popup-padding: calc(var(--base) * 0.5); - --button-size-offset: -8px; position: relative; &__trigger-wrap { @@ -18,248 +11,73 @@ cursor: pointer; } - &__content { - position: absolute; - background: var(--popup-bg); - opacity: 0; - visibility: hidden; - pointer-events: none; - z-index: var(--z-popup); - max-width: calc(100vw - #{$baseline}); - color: var(--popup-text); - border-radius: 4px; - padding-left: var(--popup-padding); - padding-right: var(--popup-padding); - min-width: var(--popup-width, auto); - } - - &__hide-scrollbar { - overflow: hidden; - } - - &__scroll-container { - overflow-y: auto; - white-space: nowrap; - width: calc(100% + var(--scrollbar-width)); - padding-top: var(--popup-padding); - padding-bottom: var(--popup-padding); - max-height: calc(var(--base) * 10); - overflow-y: auto; - } - - &__scroll-content { - width: calc(100% - var(--scrollbar-width)); - } - - &--show-scrollbar { - .popup__scroll-container, - .popup__scroll-content { - width: 100%; - } - } - - &:focus, - &:active { - outline: none; - } - - //////////////////////////////// - // SIZE - //////////////////////////////// - - &--size-xsmall { - --popup-width: 80px; - .popup__content { - @include shadow-sm; - } - } - - &--size-small { - --popup-width: 100px; - .popup__content { - @include shadow-m; - } + &__on-hover-watch { + display: contents; } + } - &--size-medium { - --popup-width: 150px; - .popup__content { - @include shadow-lg; - } - } + .popup__hidden-content { + display: none; + } - &--size-large { - --popup-width: 200px; - .popup__content { - @include shadow-lg; - } - } + .popup__content { + --popup-caret-size: 8px; + --popup-button-highlight: var(--theme-elevation-150); - //////////////////////////////// - /// BUTTON SIZE - //////////////////////////////// + position: absolute; + z-index: var(--z-popup); + background: var(--theme-input-bg); + color: var(--theme-text); + border-radius: 4px; + padding: calc(var(--base) * 0.5); + min-width: 150px; + max-width: calc(100vw - var(--base)); + @include shadow-lg; - &--button-size-xsmall { - --button-size-offset: -12px; + &.popup--size-xsmall { + min-width: 80px; } - - &--button-size-small { - --button-size-offset: -8px; + &.popup--size-small { + min-width: 100px; } - - &--button-size-medium { - --button-size-offset: -4px; + &.popup--size-large { + min-width: 200px; } - - &--button-size-large { - --button-size-offset: 0px; + &.popup--size-fit-content { + min-width: fit-content; } + } - //////////////////////////////// - // HORIZONTAL ALIGNMENT - //////////////////////////////// - [dir='rtl'] &--h-align-left { - .popup__caret { - right: var(--popup-padding); - left: unset; - } - } - &--h-align-left { - .popup__caret { - left: var(--popup-padding); - } - } - &--h-align-center { - .popup__content { - left: 50%; - transform: translateX(-50%); - } - - .popup__caret { - left: 50%; - transform: translateX(-50%); - } - } - - [dir='rtl'] &--h-align-right { - .popup__content { - right: unset; - left: 0; - } - - .popup__caret { - right: unset; - left: var(--popup-padding); - } - } - - &--h-align-right { - .popup__content { - right: var(--button-size-offset); - } - - .popup__caret { - right: var(--popup-padding); - } - } - - //////////////////////////////// - // VERTICAL ALIGNMENT - //////////////////////////////// - - &__caret { - position: absolute; - border: var(--popup-caret-size) solid transparent; - } - - &--v-align-top { - .popup__content { - @include shadow-lg; - bottom: calc(100% + var(--popup-caret-size)); - } - - .popup__caret { - top: calc(100% - 1px); - border-top-color: var(--popup-bg); - } - } + .popup__scroll-container { + overflow-y: auto; + max-height: calc(var(--base) * 10); - &--v-align-bottom { - .popup__content { - @include shadow-lg-top; - top: calc(100% + var(--popup-caret-size)); - } + &:not(.popup__scroll-container--show-scrollbar) { + scrollbar-width: none; // Firefox + -ms-overflow-style: none; // IE/Edge - .popup__caret { - bottom: calc(100% - 1px); - border-bottom-color: var(--popup-bg); + &::-webkit-scrollbar { + display: none; // Chrome/Safari/Opera } } + } - //////////////////////////////// - // ACTIVE - //////////////////////////////// + .popup__caret { + position: absolute; + width: 0; + height: 0; + border: var(--popup-caret-size) solid transparent; + left: var(--caret-left, 16px); + transform: translateX(-50%); - &--active { - .popup__content { - opacity: 1; - visibility: visible; - pointer-events: all; - } + .popup--v-bottom & { + top: calc(var(--popup-caret-size) * -2); + border-bottom-color: var(--theme-input-bg); } - @include mid-break { - --popup-padding: calc(var(--base) * 0.25); - - &--h-align-center { - .popup__content { - left: 50%; - transform: translateX(-0%); - } - - .popup__caret { - left: 50%; - transform: translateX(-0%); - } - } - - &--h-align-right { - .popup__content { - right: 0; - } - - .popup__caret { - right: var(--popup-padding); - } - } - - &--force-h-align-left { - .popup__content { - left: 0; - right: unset; - transform: unset; - } - - .popup__caret { - left: var(--popup-padding); - right: unset; - transform: unset; - } - } - - &--force-h-align-right { - .popup__content { - right: 0; - left: unset; - transform: unset; - } - - .popup__caret { - right: var(--popup-padding); - left: unset; - transform: unset; - } - } + .popup--v-top & { + bottom: calc(var(--popup-caret-size) * -2); + border-top-color: var(--theme-input-bg); } } } diff --git a/packages/ui/src/elements/Popup/index.tsx b/packages/ui/src/elements/Popup/index.tsx index 612bba20551..1cc8d526ee6 100644 --- a/packages/ui/src/elements/Popup/index.tsx +++ b/packages/ui/src/elements/Popup/index.tsx @@ -3,15 +3,33 @@ import type { CSSProperties } from 'react' export * as PopupList from './PopupButtonList/index.js' -import { useWindowInfo } from '@faceless-ui/window-info' import React, { useCallback, useEffect, useRef, useState } from 'react' +import { createPortal } from 'react-dom' -import { useIntersect } from '../../hooks/useIntersect.js' -import { PopupTrigger } from './PopupTrigger/index.js' +import { useEffectEvent } from '../../hooks/useEffectEvent.js' import './index.scss' +import { PopupTrigger } from './PopupTrigger/index.js' const baseClass = 'popup' +/** + * Selector for all elements the browser considers tabbable. + */ +const TABBABLE_SELECTOR = [ + 'a[href]', + 'button:not(:disabled)', + 'input:not(:disabled):not([type="hidden"])', + 'select:not(:disabled)', + 'textarea:not(:disabled)', + '[tabindex]', + '[contenteditable]:not([contenteditable="false"])', + 'audio[controls]', + 'video[controls]', + 'summary', +] + .map((s) => `${s}:not([tabindex="-1"])`) + .join(', ') + export type PopupProps = { backgroundColor?: CSSProperties['backgroundColor'] boundingRef?: React.RefObject @@ -23,24 +41,52 @@ export type PopupProps = { children?: React.ReactNode className?: string disabled?: boolean + /** + * Force control the open state of the popup, regardless of the trigger. + */ forceOpen?: boolean + /** + * Preferred horizontal alignment of the popup, if there is enough space available. + * + * @default 'left' + */ horizontalAlign?: 'center' | 'left' | 'right' id?: string initActive?: boolean noBackground?: boolean onToggleClose?: () => void onToggleOpen?: (active: boolean) => void - render?: (any) => React.ReactNode + render?: (args: { close: () => void }) => React.ReactNode showOnHover?: boolean + /** + * By default, the scrollbar is hidden. If you want to show it, set this to true. + * In both cases, the container is still scrollable. + * + * @default false + */ showScrollbar?: boolean size?: 'fit-content' | 'large' | 'medium' | 'small' + /** + * Preferred vertical alignment of the popup (position below or above the trigger), + * if there is enough space available. + * + * If the popup is too close to the edge of the viewport, it will flip to the opposite side + * regardless of the preferred vertical alignment. + * + * @default 'bottom' + */ verticalAlign?: 'bottom' | 'top' } +/** + * Component that renders a popup, as well as a button that triggers the popup. + * + * The popup is rendered in a portal, and is automatically positioned above / below the trigger, + * depending on the verticalAlign prop and the space available. + */ export const Popup: React.FC = (props) => { const { id, - boundingRef, button, buttonClassName, buttonSize, @@ -50,7 +96,7 @@ export const Popup: React.FC = (props) => { className, disabled, forceOpen, - horizontalAlign: horizontalAlignFromProps = 'left', + horizontalAlign = 'left', initActive = false, noBackground, onToggleClose, @@ -59,131 +105,293 @@ export const Popup: React.FC = (props) => { showOnHover = false, showScrollbar = false, size = 'medium', - verticalAlign: verticalAlignFromProps = 'top', + verticalAlign = 'bottom', } = props - const { height: windowHeight, width: windowWidth } = useWindowInfo() - const [intersectionRef, intersectionEntry] = useIntersect({ - root: boundingRef?.current || null, - rootMargin: '-100px 0px 0px 0px', - threshold: 1, - }) + const popupRef = useRef(null) + const triggerRef = useRef(null) - const contentRef = useRef(null) - const triggerRef = useRef(null) - const [active, setActive_Internal] = useState(initActive) - const [verticalAlign, setVerticalAlign] = useState(verticalAlignFromProps) - const [horizontalAlign, setHorizontalAlign] = useState(horizontalAlignFromProps) + /** + * Keeps track of whether the popup was opened via keyboard. + * This is used to determine whether to autofocus the first element in the popup. + * If the popup was opened via mouse, we do not want to autofocus the first element. + */ + const openedViaKeyboardRef = useRef(false) - const setActive = React.useCallback( - (active: boolean) => { - if (active && typeof onToggleOpen === 'function') { - onToggleOpen(true) - } - if (!active && typeof onToggleClose === 'function') { - onToggleClose() + const [mounted, setMounted] = useState(false) + const [active, setActiveInternal] = useState(initActive) + const [isOnTop, setIsOnTop] = useState(verticalAlign === 'top') + + // Track when component is mounted to avoid SSR/client hydration mismatch + useEffect(() => { + setMounted(true) + }, []) + + const setActive = useCallback( + (isActive: boolean, viaKeyboard = false) => { + if (isActive) { + openedViaKeyboardRef.current = viaKeyboard + onToggleOpen?.(true) + } else { + onToggleClose?.() } - setActive_Internal(active) + setActiveInternal(isActive) }, [onToggleClose, onToggleOpen], ) - const setPosition = useCallback( - ({ horizontal = false, vertical = false }) => { - if (contentRef.current) { - const bounds = contentRef.current.getBoundingClientRect() - - const { - bottom: contentBottomPos, - left: contentLeftPos, - right: contentRightPos, - top: contentTopPos, - } = bounds - - let boundingTopPos = 100 - let boundingRightPos = document.documentElement.clientWidth - let boundingBottomPos = document.documentElement.clientHeight - let boundingLeftPos = 0 - - if (boundingRef?.current) { - ;({ - bottom: boundingBottomPos, - left: boundingLeftPos, - right: boundingRightPos, - top: boundingTopPos, - } = boundingRef.current.getBoundingClientRect()) - } - - if (horizontal) { - if (contentRightPos > boundingRightPos && contentLeftPos > boundingLeftPos) { - setHorizontalAlign('right') - } else if (contentLeftPos < boundingLeftPos && contentRightPos < boundingRightPos) { - setHorizontalAlign('left') - } - } - - if (vertical) { - if (contentTopPos < boundingTopPos && contentBottomPos < boundingBottomPos) { - setVerticalAlign('bottom') - } else if (contentBottomPos > boundingBottomPos && contentTopPos > boundingTopPos) { - setVerticalAlign('top') - } - } + // ///////////////////////////////////// + // Position Calculation + // + // Calculates and applies popup position relative to trigger. + // Always checks viewport bounds (for flipping), but only updates + // styles if the calculated position differs from current position. + // ///////////////////////////////////// + + const updatePosition = useEffectEvent(() => { + const trigger = triggerRef.current + const popup = popupRef.current + if (!trigger || !popup) { + return + } + + const triggerRect = trigger.getBoundingClientRect() + const popupRect = popup.getBoundingClientRect() + + // Gap between the popup and the trigger/viewport edges (in pixels) + const offset = 10 + + // ///////////////////////////////////// + // Vertical Positioning + // Calculates the `top` position in absolute page coordinates. + // Uses `verticalAlign` prop as the preferred direction, but flips + // to the opposite side if there's not enough viewport space. + // ///////////////////////////////////// + + let top: number + let onTop = verticalAlign === 'top' + + if (verticalAlign === 'bottom') { + top = triggerRect.bottom + window.scrollY + offset + + if (triggerRect.bottom + popupRect.height + offset > window.innerHeight) { + top = triggerRect.top + window.scrollY - popupRect.height - offset + onTop = true } - }, - [boundingRef], - ) + } else { + top = triggerRect.top + window.scrollY - popupRect.height - offset - const handleClickOutside = useCallback( - (e) => { - if (contentRef.current.contains(e.target) || triggerRef.current.contains(e.target)) { + if (triggerRect.top - popupRect.height - offset < 0) { + top = triggerRect.bottom + window.scrollY + offset + onTop = false + } + } + + setIsOnTop(onTop) + + // ///////////////////////////////////// + // Horizontal Positioning + // Calculates the `left` position based on `horizontalAlign` prop: + // - 'left': aligns popup's left edge with trigger's left edge + // - 'right': aligns popup's right edge with trigger's right edge + // - 'center': centers popup horizontally relative to trigger + // Then clamps to keep the popup within viewport bounds. + // ///////////////////////////////////// + + let left = + horizontalAlign === 'right' + ? triggerRect.right - popupRect.width + : horizontalAlign === 'center' + ? triggerRect.left + triggerRect.width / 2 - popupRect.width / 2 + : triggerRect.left + + left = Math.max(offset, Math.min(left, window.innerWidth - popupRect.width - offset)) + + // ///////////////////////////////////// + // Caret Positioning + // Positions the caret arrow to point at the trigger's horizontal center. + // Clamps between 12px from edges to prevent caret from overflowing the popup. + // ///////////////////////////////////// + + const triggerCenter = triggerRect.left + triggerRect.width / 2 + const caretLeft = Math.max(12, Math.min(triggerCenter - left, popupRect.width - 12)) + + // ///////////////////////////////////// + // Apply Styles (only if changed) + // Compares calculated position with current styles to avoid unnecessary + // DOM updates during scroll. This prevents visual lag by relying on the absolute + // positioning where possible (popup slightly lags behind when scrolling really fast), + // while still allowing position changes when needed (e.g., sticky parent, viewport flip). + // Values are rounded to match browser's CSS precision and avoid false updates. + // ///////////////////////////////////// + + const newTop = `${Math.round(top)}px` + const newLeft = `${Math.round(left + window.scrollX)}px` + const newCaretLeft = `${Math.round(caretLeft)}px` + + if (popup.style.top !== newTop) { + popup.style.top = newTop + } + if (popup.style.left !== newLeft) { + popup.style.left = newLeft + } + if (popup.style.getPropertyValue('--caret-left') !== newCaretLeft) { + popup.style.setProperty('--caret-left', newCaretLeft) + } + }) + + // ///////////////////////////////////// + // Click Outside Handler + // Closes popup when clicking outside both the popup and trigger. + // ///////////////////////////////////// + + const handleClickOutside = useEffectEvent((e: MouseEvent) => { + const isOutsidePopup = !popupRef.current?.contains(e.target as Node) + const isOutsideTrigger = !triggerRef.current?.contains(e.target as Node) + + if (isOutsidePopup && isOutsideTrigger) { + setActive(false) + } + }) + + // ///////////////////////////////////// + // Keyboard Navigation + // Handles keyboard interactions when popup is open: + // - Escape: closes popup and returns focus to trigger + // - Tab/Shift+Tab: cycles through focusable items with wrapping + // - ArrowUp/ArrowDown: same as Shift+Tab/Tab for menu-style navigation + // Focus is managed manually to support elements the browser might skip. + // ///////////////////////////////////// + + const handleKeyDown = useEffectEvent((e: KeyboardEvent) => { + const popup = popupRef.current + if (!popup || !active) { + return + } + + if (e.key === 'Escape') { + e.preventDefault() + setActive(false) + triggerRef.current?.querySelector('button, [tabindex="0"]')?.focus() + return + } + + if (e.key === 'Tab' || e.key === 'ArrowDown' || e.key === 'ArrowUp') { + const focusable = Array.from(popup.querySelectorAll(TABBABLE_SELECTOR)) + if (focusable.length === 0) { return } + e.preventDefault() + + const currentIndex = focusable.findIndex((el) => el === document.activeElement) + const goBackward = e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey) + + let nextIndex: number + if (currentIndex === -1) { + nextIndex = goBackward ? focusable.length - 1 : 0 + } else if (goBackward) { + nextIndex = currentIndex === 0 ? focusable.length - 1 : currentIndex - 1 + } else { + nextIndex = currentIndex === focusable.length - 1 ? 0 : currentIndex + 1 + } + + focusable[nextIndex].focus() + } + }) + + // ///////////////////////////////////// + // Click Handler for Actionable Elements + // Closes popup when buttons/links inside are clicked (includes Enter/Space activation). + // ///////////////////////////////////// + + const handleActionableClick = useEffectEvent((e: MouseEvent) => { + const target = e.target as HTMLElement + // Check if the clicked element or any ancestor is an actionable element + const actionable = target.closest('button, a[href], [role="button"], [role="menuitem"]') + if (actionable && popupRef.current?.contains(actionable)) { setActive(false) - }, - [contentRef, setActive], - ) + } + }) - useEffect(() => { - setPosition({ horizontal: true }) - }, [intersectionEntry, setPosition, windowWidth]) + // ///////////////////////////////////// + // Effect: Setup/Teardown position and focus management + // ///////////////////////////////////// useEffect(() => { - setPosition({ vertical: true }) - }, [intersectionEntry, setPosition, windowHeight]) + if (!active) { + return + } - useEffect(() => { - if (active) { - document.addEventListener('mousedown', handleClickOutside) - } else { - document.removeEventListener('mousedown', handleClickOutside) + const popup = popupRef.current + if (!popup) { + return } + // ///////////////////////////////////// + // Initial Position + // Calculate and apply popup position immediately on open. + // ///////////////////////////////////// + + updatePosition() + + // ///////////////////////////////////// + // Focus Management + // When opened via keyboard, autofocus the first focusable button. + // When opened via mouse, skip autofocus to avoid unwanted highlights. + // ///////////////////////////////////// + + if (openedViaKeyboardRef.current) { + // Use requestAnimationFrame to ensure DOM is ready. + requestAnimationFrame(() => { + const firstFocusable = popup.querySelector(TABBABLE_SELECTOR) + firstFocusable?.focus() + }) + } + + // ///////////////////////////////////// + // Event Listeners + // - resize/scroll: recalculate position (only applies styles if changed) + // - mousedown: detect clicks outside to close + // - keydown: handle keyboard navigation + // ///////////////////////////////////// + + window.addEventListener('resize', updatePosition) + window.addEventListener('scroll', updatePosition, { capture: true, passive: true }) + document.addEventListener('mousedown', handleClickOutside) + document.addEventListener('keydown', handleKeyDown) + popup.addEventListener('click', handleActionableClick) + return () => { + window.removeEventListener('resize', updatePosition) + window.removeEventListener('scroll', updatePosition, { capture: true }) document.removeEventListener('mousedown', handleClickOutside) + document.removeEventListener('keydown', handleKeyDown) + popup.removeEventListener('click', handleActionableClick) } - }, [active, handleClickOutside, onToggleOpen]) + }, [active]) useEffect(() => { - setActive(forceOpen) + if (forceOpen !== undefined) { + setActive(forceOpen) + } }, [forceOpen, setActive]) - const classes = [ - baseClass, - className, - `${baseClass}--size-${size}`, - buttonSize && `${baseClass}--button-size-${buttonSize}`, - `${baseClass}--v-align-${verticalAlign}`, - `${baseClass}--h-align-${horizontalAlign}`, - active && `${baseClass}--active`, - showScrollbar && `${baseClass}--show-scrollbar`, - ] - .filter(Boolean) - .join(' ') + const Trigger = ( + + ) return ( -
+
{showOnHover ? (
= (props) => { role="button" tabIndex={0} > - + {Trigger}
) : ( - + Trigger )}
-
-
-
-
- {render && render({ close: () => setActive(false) })} - {children} -
-
-
- - {caret &&
} -
+ {mounted + ? // We need to make sure the popup is part of the DOM (although invisible), even if it's not active. + // This ensures that components within the popup, like modals, do not unmount when the popup closes. + // Otherwise, modals opened from the popup will close unexpectedly when clicking within the modal, since + // that closes the popup due to the click outside handler. + createPortal( +
+
+ {render?.({ close: () => setActive(false) })} + {children} +
+ {caret &&
} +
, + document.body, + ) + : null}
) } diff --git a/packages/ui/src/scss/app.scss b/packages/ui/src/scss/app.scss index f663bfc3991..7e99e7c32b6 100644 --- a/packages/ui/src/scss/app.scss +++ b/packages/ui/src/scss/app.scss @@ -31,7 +31,8 @@ --style-radius-m: #{$style-radius-m}; --style-radius-l: #{$style-radius-l}; - --z-popup: 10; + // --z-popup needs to be higher than --z-modal to ensure the popup is displayed when modal is open + --z-popup: 60; --z-nav: 20; --z-modal: 30; --z-status: 40; diff --git a/test/admin/e2e/document-view/e2e.spec.ts b/test/admin/e2e/document-view/e2e.spec.ts index 93edd879e51..52d1e072d7b 100644 --- a/test/admin/e2e/document-view/e2e.spec.ts +++ b/test/admin/e2e/document-view/e2e.spec.ts @@ -766,7 +766,7 @@ describe('Document View', () => { await expect(threeDotMenu).toBeVisible() await threeDotMenu.click() - const customEditMenuItem = page.locator('.popup-button-list__button', { + const customEditMenuItem = page.locator('.popup__content .popup-button-list__button', { hasText: 'Custom Edit Menu Item', }) @@ -782,7 +782,7 @@ describe('Document View', () => { await expect(threeDotMenu).toBeVisible() await threeDotMenu.click() - const popup = page.locator('.popup--active .popup__content') + const popup = page.locator('.popup__content') await expect(popup).toBeVisible() const customEditMenuItem = popup.getByRole('link', { @@ -801,7 +801,7 @@ describe('Document View', () => { await expect(threeDotMenu).toBeVisible() await threeDotMenu.click() - const popup = page.locator('.popup--active .popup__content') + const popup = page.locator('.popup__content') await expect(popup).toBeVisible() const customEditMenuItem = popup.getByRole('link', { diff --git a/test/admin/e2e/general/e2e.spec.ts b/test/admin/e2e/general/e2e.spec.ts index eadf4c55600..99243236285 100644 --- a/test/admin/e2e/general/e2e.spec.ts +++ b/test/admin/e2e/general/e2e.spec.ts @@ -525,7 +525,7 @@ describe('General', () => { await openNav(page) const gearButton = page.locator('.nav__controls .popup#settings-menu .popup-button') await gearButton.click() - const popupContent = page.locator('.popup#settings-menu .popup__content') + const popupContent = page.locator('.popup__content') await expect(popupContent).toBeVisible() }) @@ -535,21 +535,17 @@ describe('General', () => { const gearButton = page.locator('.nav__controls .popup#settings-menu .popup-button') await gearButton.click() + const popupButtons = page.locator( + '[data-popup-id="settings-menu"] .popup-button-list__button', + ) + // Check for the first group of buttons - await expect( - page.locator('.popup#settings-menu .popup-button-list__button').first(), - ).toContainText('System Settings') - await expect( - page.locator('.popup#settings-menu .popup-button-list__button').nth(1), - ).toContainText('View Logs') + await expect(popupButtons.first()).toContainText('System Settings') + await expect(popupButtons.nth(1)).toContainText('View Logs') // Check for the second group of buttons - await expect( - page.locator('.popup#settings-menu .popup-button-list__button').nth(2), - ).toContainText('Manage Users') - await expect( - page.locator('.popup#settings-menu .popup-button-list__button').nth(3), - ).toContainText('View Activity') + await expect(popupButtons.nth(2)).toContainText('Manage Users') + await expect(popupButtons.nth(3)).toContainText('View Activity') }) test('breadcrumbs — should navigate from list to dashboard', async () => { @@ -787,7 +783,7 @@ describe('General', () => { }) test('should allow custom translation of locale labels', async () => { - const selectOptionClass = '.localizer .popup-button-list__button' + const selectOptionClass = '.popup__content .popup-button-list__button' const localizerButton = page.locator('.localizer .popup-button') const localeListItem1 = page.locator(selectOptionClass).nth(0) diff --git a/test/admin/e2e/list-view/e2e.spec.ts b/test/admin/e2e/list-view/e2e.spec.ts index 9c738ca7ce9..ecb1e21cb84 100644 --- a/test/admin/e2e/list-view/e2e.spec.ts +++ b/test/admin/e2e/list-view/e2e.spec.ts @@ -256,9 +256,12 @@ describe('List View', () => { await kebabMenu.click() await expect( - page.locator('.popup-button-list').locator('div', { - hasText: 'listMenuItems', - }), + page + .locator('.popup-button-list') + .locator('div', { + hasText: 'listMenuItems', + }) + .first(), ).toBeVisible() }) @@ -1525,8 +1528,7 @@ describe('List View', () => { await page.goto(postsUrl.list) await page.locator('.per-page .popup-button').click() - await page.locator('.per-page .popup-button').click() - const options = page.locator('.per-page button.per-page__button') + const options = page.locator('.popup__content button.per-page__button') await expect(options).toHaveCount(3) await expect(options.nth(0)).toContainText('5') await expect(options.nth(1)).toContainText('10') @@ -1567,7 +1569,7 @@ describe('List View', () => { await page.locator('.per-page .popup-button').click() await page - .locator('.per-page button.per-page__button', { + .locator('.popup__content button.per-page__button', { hasText: '15', }) .click() diff --git a/test/fields/collections/Array/e2e.spec.ts b/test/fields/collections/Array/e2e.spec.ts index 6fb7ae24120..e7612aa79d4 100644 --- a/test/fields/collections/Array/e2e.spec.ts +++ b/test/fields/collections/Array/e2e.spec.ts @@ -485,7 +485,7 @@ describe('Array', () => { ) await arrayFieldPopupBtn.click() const disabledCopyBtn = page.locator( - '#field-collapsedArray .popup.clipboard-action__popup .popup__content div.popup-button-list__disabled:has-text("Copy Field")', + '.popup__content div.popup-button-list__disabled:has-text("Copy Field")', ) await expect(disabledCopyBtn).toBeVisible() }) @@ -502,7 +502,7 @@ describe('Array', () => { await expect(popupBtn).toBeVisible() await popupBtn.click() const disabledPasteBtn = page.locator( - '#field-readOnly .popup.clipboard-action__popup .popup__content div.popup-button-list__disabled:has-text("Paste Field")', + '.popup__content div.popup-button-list__disabled:has-text("Paste Field")', ) await expect(disabledPasteBtn).toBeVisible() }) diff --git a/test/fields/collections/Blocks/e2e.spec.ts b/test/fields/collections/Blocks/e2e.spec.ts index eb2514bd2b4..bbbb7f96986 100644 --- a/test/fields/collections/Blocks/e2e.spec.ts +++ b/test/fields/collections/Blocks/e2e.spec.ts @@ -502,7 +502,7 @@ describe('Block fields', () => { ) await popupBtn.click() const disabledCopyBtn = page.locator( - '#field-i18nBlocks .popup.clipboard-action__popup .popup__content div.popup-button-list__disabled:has-text("Copy Field")', + '.popup__content div.popup-button-list__disabled:has-text("Copy Field")', ) await expect(disabledCopyBtn).toBeVisible() }) @@ -519,7 +519,7 @@ describe('Block fields', () => { await expect(popupBtn).toBeVisible() await popupBtn.click() const disabledPasteBtn = page.locator( - '#field-readOnly .popup.clipboard-action__popup .popup__content div.popup-button-list__disabled:has-text("Paste Field")', + '.popup__content div.popup-button-list__disabled:has-text("Paste Field")', ) await expect(disabledPasteBtn).toBeVisible() }) diff --git a/test/fields/collections/Relationship/e2e.spec.ts b/test/fields/collections/Relationship/e2e.spec.ts index 0ca0fa97cb1..e89ba633dc2 100644 --- a/test/fields/collections/Relationship/e2e.spec.ts +++ b/test/fields/collections/Relationship/e2e.spec.ts @@ -82,7 +82,7 @@ describe('relationship', () => { await loadCreatePage() await openCreateDocDrawer({ page, fieldSelector: '#field-relationship' }) await page - .locator('#field-relationship .relationship-add-new__relation-button--text-fields') + .locator('.popup__content .relationship-add-new__relation-button--text-fields') .click() const textField = page.locator('.drawer__content #field-text') await expect(textField).toBeEnabled() @@ -105,7 +105,7 @@ describe('relationship', () => { // Select the SECOND collection (array-fields) instead of the first (text-fields) await page - .locator('#field-relationship .relationship-add-new__relation-button--array-fields') + .locator('.popup__content .relationship-add-new__relation-button--array-fields') .click() await page.locator('[id^=doc-drawer_array-fields_1_] #action-save').click() @@ -331,7 +331,7 @@ describe('relationship', () => { // First fill out the relationship field, as it's required await openCreateDocDrawer({ page, fieldSelector: '#field-relationship' }) await page - .locator('#field-relationship .relationship-add-new__relation-button--text-fields') + .locator('.popup__content .relationship-add-new__relation-button--text-fields') .click() await page.locator('.drawer__content #field-text').fill('something') @@ -491,8 +491,8 @@ describe('relationship', () => { }) const drawer1Content = page.locator('[id^=doc-drawer_text-fields_1_] .drawer__content') const originalDrawerID = await drawer1Content.locator('.id-label').textContent() - await openDocControls(drawer1Content) - await drawer1Content.locator('#action-create').click() + await openDocControls(drawer1Content, page) + await page.locator('.popup__content #action-create').click() await wait(1000) // wait for /form-state to return const title = 'Created from drawer' await drawer1Content.locator('#field-text').fill(title) @@ -551,8 +551,8 @@ describe('relationship', () => { const originalText = 'Text' await drawer1Content.locator('#field-text').fill(originalText) await saveDocAndAssert(page, '[id^=doc-drawer_text-fields_1_] .drawer__content #action-save') - await openDocControls(drawer1Content) - await drawer1Content.locator('#action-duplicate').click() + await openDocControls(drawer1Content, page) + await page.locator('.popup__content #action-duplicate').click() const duplicateID = drawer1Content.locator('.id-label') await expect(duplicateID).not.toHaveText(originalID) await page.locator('[id^=doc-drawer_text-fields_1_] .drawer__close').click() @@ -608,8 +608,8 @@ describe('relationship', () => { const drawer1Content = page.locator('[id^=doc-drawer_text-fields_1_] .drawer__content') const originalID = await drawer1Content.locator('.id-label').textContent() - await openDocControls(drawer1Content) - await drawer1Content.locator('#action-delete').click() + await openDocControls(drawer1Content, page) + await page.locator('.popup__content #action-delete').click() await page .locator('[id^=delete-].payload__modal-item.confirmation-modal[open] button#confirm-action') diff --git a/test/folders/e2e.spec.ts b/test/folders/e2e.spec.ts index c13698d681c..fe1702b3211 100644 --- a/test/folders/e2e.spec.ts +++ b/test/folders/e2e.spec.ts @@ -207,7 +207,7 @@ test.describe('Folders', () => { await expect(createDocButton).toBeVisible() await createDocButton.click() const postButton = page - .locator('.popup--active') + .locator('.popup__content') .locator('.popup-button-list__button', { hasText: 'Post' }) await expect(postButton).toBeVisible() await postButton.click() @@ -290,7 +290,7 @@ test.describe('Folders', () => { hasText: 'Create New', }) await createNewDropdown.click() - const createFolderButton = page.locator('.popup-button-list__button').first() + const createFolderButton = page.locator('.popup__content .popup-button-list__button').first() await createFolderButton.click() await createFolderDoc({ page, @@ -300,7 +300,9 @@ test.describe('Folders', () => { await expect(page.locator('.folder-file-card__name')).toHaveText('Nested Folder') await createNewDropdown.click() - const createPostButton = page.locator('.popup-button-list__button', { hasText: 'Post' }) + const createPostButton = page.locator('.popup__content .popup-button-list__button', { + hasText: 'Post', + }) await createPostButton.click() const postTitleInput = page.locator('input[id="field-title"]') @@ -612,10 +614,9 @@ test.describe('Folders', () => { hasText: 'Create New', }) await createNewDropdown.click() - const createFolderButton = page.locator( - '.list-header__title-actions .popup-button-list__button', - { hasText: 'Folder' }, - ) + const createFolderButton = page.locator('.popup__content .popup-button-list__button', { + hasText: 'Folder', + }) await createFolderButton.click() const drawer = page.locator('dialog .collection-edit--payload-folders') @@ -671,12 +672,9 @@ test.describe('Folders', () => { ) await expect(folderDropdown).toBeVisible() await folderDropdown.click() - const createFolderButton = page.locator( - '.list-header__title-actions .popup-button-list__button', - { - hasText: 'Folder', - }, - ) + const createFolderButton = page.locator('.popup__content .popup-button-list__button', { + hasText: 'Folder', + }) await createFolderButton.click() const drawer = page.locator('dialog .collection-edit--payload-folders') @@ -709,10 +707,9 @@ test.describe('Folders', () => { hasText: 'Create New', }) await createNewDropdown.click() - const createFolderButton = page.locator( - '.list-header__title-actions .popup-button-list__button', - { hasText: 'Folder' }, - ) + const createFolderButton = page.locator('.popup__content .popup-button-list__button', { + hasText: 'Folder', + }) await createFolderButton.click() const drawer = page.locator('dialog .collection-edit--payload-folders') diff --git a/test/helpers.ts b/test/helpers.ts index f6d59270ba0..995944c055e 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -219,7 +219,7 @@ export async function openCreateDocDrawer(page: Page, fieldSelector: string): Pr export async function openLocaleSelector(page: Page): Promise { const button = page.locator('.localizer button.popup-button') - const popup = page.locator('.localizer .popup.popup--active') + const popup = page.locator('.popup__content') if (!(await popup.isVisible())) { await button.click() @@ -228,7 +228,7 @@ export async function openLocaleSelector(page: Page): Promise { } export async function closeLocaleSelector(page: Page): Promise { - const popup = page.locator('.localizer .popup.popup--active') + const popup = page.locator('.popup__content') if (await popup.isVisible()) { await page.click('body', { position: { x: 0, y: 0 } }) @@ -240,14 +240,12 @@ export async function changeLocale(page: Page, newLocale: string) { await openLocaleSelector(page) const currentlySelectedLocale = await page - .locator( - `.localizer .popup.popup--active .popup-button-list__button--selected .localizer__locale-code`, - ) + .locator(`.popup__content .popup-button-list__button--selected .localizer__locale-code`) .textContent() if (currentlySelectedLocale !== `(${newLocale})`) { const localeToSelect = page - .locator('.localizer .popup.popup--active .popup-button-list__button') + .locator('.popup__content .popup-button-list__button') .locator('.localizer__locale-code', { hasText: `${newLocale}`, }) diff --git a/test/helpers/e2e/copyPasteField.ts b/test/helpers/e2e/copyPasteField.ts index b633b75e9dc..65dbde14572 100644 --- a/test/helpers/e2e/copyPasteField.ts +++ b/test/helpers/e2e/copyPasteField.ts @@ -31,9 +31,9 @@ export async function copyPasteField({ await popupBtn.click() const actionBtnSelector = rowAction - ? `#${fieldName}-row-${rowIndex} .popup__content .popup-button-list button.array-actions__${action}` - : `.popup.clipboard-action__popup .popup__content .popup-button-list button:has-text("${isCopy ? 'Copy' : 'Paste'} Field")` - const actionBtn = field.locator(actionBtnSelector).first() + ? `.popup__content .popup-button-list button.array-actions__${action}` + : `.popup__content .popup-button-list button:has-text("${isCopy ? 'Copy' : 'Paste'} Field")` + const actionBtn = page.locator(actionBtnSelector).first() await expect(actionBtn).toBeVisible() await actionBtn.click() diff --git a/test/helpers/e2e/fields/array/openArrayRowActions.ts b/test/helpers/e2e/fields/array/openArrayRowActions.ts index 9e252738ac6..13f11f23e91 100644 --- a/test/helpers/e2e/fields/array/openArrayRowActions.ts +++ b/test/helpers/e2e/fields/array/openArrayRowActions.ts @@ -26,7 +26,7 @@ export const openArrayRowActions = async ( .locator(`#field-${fieldName} #${formattedRowID}-row-${rowIndex} .array-actions`) .first() - const popupContentLocator = rowActions.locator('.popup__content') + const popupContentLocator = page.locator('.popup__content') if (await popupContentLocator.isVisible()) { throw new Error(`Row actions for field "${fieldName}" at index ${rowIndex} are already open.`) diff --git a/test/helpers/e2e/live-preview/selectLivePreviewBreakpoint.ts b/test/helpers/e2e/live-preview/selectLivePreviewBreakpoint.ts index dc29b7097fe..2b78f3e74a6 100644 --- a/test/helpers/e2e/live-preview/selectLivePreviewBreakpoint.ts +++ b/test/helpers/e2e/live-preview/selectLivePreviewBreakpoint.ts @@ -15,15 +15,13 @@ export const selectLivePreviewBreakpoint = async (page: Page, breakpointLabel: s await breakpointSelector.first().click() await page - .locator(`.live-preview-toolbar-controls__breakpoint button.popup-button-list__button`) + .locator('.popup__content .popup-button-list__button') .filter({ hasText: breakpointLabel }) .click() await expect(breakpointSelector).toContainText(breakpointLabel) - const option = page.locator( - '.live-preview-toolbar-controls__breakpoint button.popup-button-list__button--selected', - ) + const option = page.locator('.live-preview-toolbar-controls__breakpoint button.popup-button') await expect(option).toHaveText(breakpointLabel) } diff --git a/test/helpers/e2e/live-preview/selectLivePreviewZoom.ts b/test/helpers/e2e/live-preview/selectLivePreviewZoom.ts index 99161d3f448..dfc8288a601 100644 --- a/test/helpers/e2e/live-preview/selectLivePreviewZoom.ts +++ b/test/helpers/e2e/live-preview/selectLivePreviewZoom.ts @@ -13,21 +13,12 @@ export const selectLivePreviewZoom = async (page: Page, zoomLabel: string) => { await zoomSelector.first().click() - const zoomOption = page.locator( - '.live-preview-toolbar-controls__zoom button.popup-button-list__button', - { - hasText: exactText(zoomLabel), - }, - ) + const zoomOption = page.locator('.popup__content button.popup-button-list__button', { + hasText: exactText(zoomLabel), + }) expect(zoomOption).toBeTruthy() await zoomOption.click() await expect(zoomSelector).toContainText(zoomLabel) - - const option = page.locator( - '.live-preview-toolbar-controls__zoom button.popup-button-list__button--selected', - ) - - await expect(option).toHaveText(zoomLabel) } diff --git a/test/helpers/e2e/openDocControls.ts b/test/helpers/e2e/openDocControls.ts index 984dfd67dff..4e04e97795b 100644 --- a/test/helpers/e2e/openDocControls.ts +++ b/test/helpers/e2e/openDocControls.ts @@ -1,6 +1,9 @@ import { expect, type Locator, type Page } from '@playwright/test' -export async function openDocControls(page: Locator | Page): Promise { - await page.locator('.doc-controls__popup >> .popup-button').click() - await expect(page.locator('.doc-controls__popup >> .popup__content')).toBeVisible() +export async function openDocControls( + page: Locator | Page, + mainPage?: Locator | Page, +): Promise { + await page.locator('.doc-controls__popup .popup-button').click() + await expect((mainPage ?? page).locator('.popup__content')).toBeVisible() } diff --git a/test/helpers/folders/applyBrowseByFolderTypeFilter.ts b/test/helpers/folders/applyBrowseByFolderTypeFilter.ts index 1cdbefe63cd..130b3184a5f 100644 --- a/test/helpers/folders/applyBrowseByFolderTypeFilter.ts +++ b/test/helpers/folders/applyBrowseByFolderTypeFilter.ts @@ -16,14 +16,14 @@ export const applyBrowseByFolderTypeFilter = async ({ let typePill = page.locator('.search-bar__actions .checkbox-popup.popup--active', { hasText: 'Type', }) - const isActive = (await typePill.count()) > 0 + const isActive = (await page.locator('.popup__content').count()) > 0 if (!isActive) { typePill = page.locator('.search-bar__actions .checkbox-popup', { hasText: 'Type' }) await typePill.locator('.popup-button', { hasText: 'Type' }).click() } - await typePill.locator('.field-label', { hasText: type.label }).click() + await page.locator('.popup__content .field-label', { hasText: type.label }).click() await page.waitForURL((urlStr) => { try { diff --git a/test/helpers/folders/createFolder.ts b/test/helpers/folders/createFolder.ts index 331e014702b..28d740d77aa 100644 --- a/test/helpers/folders/createFolder.ts +++ b/test/helpers/folders/createFolder.ts @@ -20,7 +20,7 @@ export async function createFolder({ hasText: 'Create', }) await folderDropdown.click() - const createFolderButton = titleActionsLocator.locator('.popup-button-list__button', { + const createFolderButton = page.locator('.popup__content .popup-button-list__button', { hasText: 'Folder', }) await createFolderButton.click() diff --git a/test/joins/e2e.spec.ts b/test/joins/e2e.spec.ts index 1fba95bf664..ce3c63f31be 100644 --- a/test/joins/e2e.spec.ts +++ b/test/joins/e2e.spec.ts @@ -472,7 +472,7 @@ describe('Join Field', () => { const popupButton = drawer.locator('.doc-controls__popup button.popup-button') await expect(popupButton).toBeVisible() await popupButton.click() - const deleteButton = drawer.locator('#action-delete') + const deleteButton = page.locator('.popup__content #action-delete') await expect(deleteButton).toBeVisible() await deleteButton.click() const deleteConfirmModal = page.locator('dialog[id^="delete-"][open]') @@ -630,7 +630,9 @@ describe('Join Field', () => { const addNewPopupBtn = joinField.locator('.relationship-table__add-new-polymorphic') await expect(addNewPopupBtn).toBeVisible() await addNewPopupBtn.click() - const pageOption = joinField.locator('.relationship-table__relation-button--example-pages') + const pageOption = page.locator( + '.popup__content .relationship-table__relation-button--example-pages', + ) await expect(pageOption).toHaveText('Example Page') await pageOption.click() await page.locator('.drawer__content input#field-title').fill('Some new page') diff --git a/test/lexical/collections/Lexical/e2e/main/e2e.spec.ts b/test/lexical/collections/Lexical/e2e/main/e2e.spec.ts index 83ddf3ee655..d472e39406c 100644 --- a/test/lexical/collections/Lexical/e2e/main/e2e.spec.ts +++ b/test/lexical/collections/Lexical/e2e/main/e2e.spec.ts @@ -1442,9 +1442,9 @@ describe('lexicalMain', () => { // Move block 1 to the end await page.locator('#blocks-row-0 .array-actions__button').click() - await expect(page.locator('#blocks-row-0 .popup__content')).toBeVisible() + await expect(page.locator('.popup__content')).toBeVisible() - await page.locator('#blocks-row-0 .popup__content').getByText('Move Down').click() + await page.locator('.popup__content').getByText('Move Down').click() await expect(page.locator('#blocks-row-0 .LexicalEditorTheme__paragraph')).toContainText('2') await expect(page.locator('#blocks-row-0 .section-title__input')).toHaveValue('2') // block name diff --git a/test/lexical/collections/RichText/e2e.spec.ts b/test/lexical/collections/RichText/e2e.spec.ts index 2fcace2d748..443935cc76f 100644 --- a/test/lexical/collections/RichText/e2e.spec.ts +++ b/test/lexical/collections/RichText/e2e.spec.ts @@ -309,7 +309,7 @@ describe('Rich Text', () => { // Open link popup await page.locator('#field-richText span >> text="render links"').click() - const popup = page.locator('.popup--active .rich-text-link__popup') + const popup = page.locator('.popup__content .rich-text-link__popup') await expect(popup).toBeVisible() await expect(popup.locator('a')).toHaveAttribute('href', 'https://payloadcms.com') @@ -333,7 +333,7 @@ describe('Rich Text', () => { // Open link popup await page.locator('#field-richText span >> text="link to relationships"').click() - const popup = page.locator('.popup--active .rich-text-link__popup') + const popup = page.locator('.popup__content .rich-text-link__popup') await expect(popup).toBeVisible() await expect(popup.locator('a')).toHaveAttribute( 'href', @@ -418,7 +418,7 @@ describe('Rich Text', () => { await wait(500) const editBlock = page.locator('#blocks-row-0 .popup-button') await editBlock.click() - const removeButton = page.locator('#blocks-row-0').getByRole('button', { name: 'Remove' }) + const removeButton = page.locator('.popup__content').getByRole('button', { name: 'Remove' }) await expect(removeButton).toBeVisible() await wait(500) await removeButton.click() diff --git a/test/localization/e2e.spec.ts b/test/localization/e2e.spec.ts index b356db51ef2..c3b7297578f 100644 --- a/test/localization/e2e.spec.ts +++ b/test/localization/e2e.spec.ts @@ -121,14 +121,15 @@ describe('Localization', () => { await page.goto(url.create) await expect(page.locator('.localizer.app-header__localizer')).toBeVisible() await page.locator('.localizer >> button').first().click() - await expect(page.locator('.localizer .popup.popup--active')).toBeVisible() + await expect(page.locator('.popup__content')).toBeVisible() }) test('should filter locale with filterAvailableLocales', async () => { await page.goto(url.create) await expect(page.locator('.localizer.app-header__localizer')).toBeVisible() await page.locator('.localizer >> button').first().click() - await expect(page.locator('.localizer .popup.popup--active')).not.toContainText('FILTERED') + await expect(page.locator('.popup__content')).toBeVisible() + await expect(page.locator('.popup__content')).not.toContainText('FILTERED') }) test('should filter version locale selector with filterAvailableLocales', async () => { @@ -154,11 +155,9 @@ describe('Localization', () => { await page.locator('.localizer button.popup-button').first().click() - await expect(page.locator('.localizer .popup')).toHaveClass(/popup--active/) + await expect(page.locator('.popup__content')).toBeVisible() - const activeOption = page.locator( - `.localizer .popup.popup--active .popup-button-list__button--selected`, - ) + const activeOption = page.locator(`.popup__content .popup-button-list__button--selected`) await expect(activeOption).toBeVisible() const tagName = await activeOption.evaluate((node) => node.tagName) @@ -545,7 +544,7 @@ describe('Localization', () => { await openLocaleSelector(page) const localeToSelect = page - .locator('.localizer .popup.popup--active .popup-button-list__button') + .locator('.popup__content .popup-button-list__button') .locator('.localizer__locale-code', { hasText: `${spanishLocale}`, }) @@ -721,6 +720,37 @@ describe('Localization', () => { await changeLocale(page, defaultLocale) await expect(page.locator('#field-title')).toBeEmpty() }) + + test('blocks - ensure publish locale popup is visible on smaller screen sizes', async () => { + // This verifies that the Popup component is not hidden behind overflow: hidden of the parent element, + // which is set for smaller screen sizes. + // This was an issue until createPortal was introduced in the Popup component. + await page.setViewportSize({ width: 480, height: 720 }) + await page.goto(urlBlocks.create) + await page.locator('.form-submit .popup-button').click() + + const popup = page.locator('.popup__content') + await expect(popup).toBeVisible() + + // Verify popup is actually visible (not clipped by overflow: hidden) + // by checking if elementFromPoint at popup's center returns the popup or its child + const box = await popup.boundingBox() + expect(box).not.toBeNull() + + const centerX = box!.x + box!.width / 2 + const centerY = box!.y + box!.height / 2 + + const isActuallyVisible = await page.evaluate( + ({ selector, x, y }) => { + const popup = document.querySelector(selector) + const elementAtPoint = document.elementFromPoint(x, y) + return popup?.contains(elementAtPoint) ?? false + }, + { selector: '.popup__content', x: centerX, y: centerY }, + ) + + expect(isActuallyVisible).toBe(true) + }) }) test('should not show publish specific locale button when no localized fields exist', async () => { diff --git a/test/plugin-multi-tenant/e2e.spec.ts b/test/plugin-multi-tenant/e2e.spec.ts index 2ae20aca7d2..b52d82f939b 100644 --- a/test/plugin-multi-tenant/e2e.spec.ts +++ b/test/plugin-multi-tenant/e2e.spec.ts @@ -719,8 +719,8 @@ async function openAssignTenantModal({ } // Open the assign tenant modal - const docControlsPopup = page.locator('.doc-controls__popup') - const docControlsButton = docControlsPopup.locator('.popup-button') + const docControlsPopup = page.locator('.popup__content') + const docControlsButton = page.locator('.doc-controls__popup .popup-button') await expect(docControlsButton).toBeVisible() await docControlsButton.click() diff --git a/test/trash/e2e.spec.ts b/test/trash/e2e.spec.ts index 1d24f6a1674..8b5aac34053 100644 --- a/test/trash/e2e.spec.ts +++ b/test/trash/e2e.spec.ts @@ -175,7 +175,7 @@ describe('Trash', () => { await expect(threeDotMenu).toBeVisible() await threeDotMenu.click() - await page.locator('.doc-controls__popup #action-delete').click() + await page.locator('.popup__content #action-delete').click() await expect(page.locator('#delete-forever')).toBeHidden() }) @@ -186,7 +186,7 @@ describe('Trash', () => { await expect(threeDotMenu).toBeVisible() await threeDotMenu.click() - await page.locator('.doc-controls__popup #action-delete').click() + await page.locator('.popup__content #action-delete').click() await expect(page.locator('#delete-forever')).toBeVisible() }) @@ -197,7 +197,7 @@ describe('Trash', () => { await expect(threeDotMenuOne).toBeVisible() await threeDotMenuOne.click() - await page.locator('.doc-controls__popup #action-delete').click() + await page.locator('.popup__content #action-delete').click() // Check the checkbox to delete permanently await page.locator('#delete-forever').check() @@ -214,7 +214,7 @@ describe('Trash', () => { await expect(threeDotMenuTwo).toBeVisible() await threeDotMenuTwo.click() - await page.locator('.doc-controls__popup #action-delete').click() + await page.locator('.popup__content #action-delete').click() // Skip the checkbox to delete permanently and default to trashing diff --git a/test/versions/e2e.spec.ts b/test/versions/e2e.spec.ts index f81f60ae4d6..9b693a6d3fa 100644 --- a/test/versions/e2e.spec.ts +++ b/test/versions/e2e.spec.ts @@ -1200,7 +1200,7 @@ describe('Versions', () => { const publishOptions = page.locator('.doc-controls__controls .popup') await publishOptions.click() - const publishSpecificLocale = page.locator('.doc-controls__controls .popup__content') + const publishSpecificLocale = page.locator('.popup__content') await expect(publishSpecificLocale).toContainText('English') }) @@ -1644,7 +1644,7 @@ describe('Versions', () => { const publishOptions = page.locator('.doc-controls__controls .popup') await publishOptions.click() - const publishSpecificLocale = page.locator('.doc-controls__controls .popup__content') + const publishSpecificLocale = page.locator('.popup__content') await expect(publishSpecificLocale).toContainText('English') }) @@ -2369,7 +2369,7 @@ describe('Versions', () => { await publishDropdown.click() const schedulePublishButton = page.locator( - '.popup-button-list__button:has-text("Schedule Publish")', + '.popup__content .popup-button-list__button:has-text("Schedule Publish")', ) await schedulePublishButton.click() From 5e1949c8c22c49d31a23bfe2a9d632b9da6798b7 Mon Sep 17 00:00:00 2001 From: Jarrod Flesch <30633324+JarrodMFlesch@users.noreply.github.com> Date: Tue, 16 Dec 2025 08:27:17 -0500 Subject: [PATCH 16/67] fix: missing range headers (#14887) ## Summary Adds HTTP Range request support (RFC 7233) to Payload's core file serving, enabling video streaming with scrubbing/seeking capabilities in browsers. ## Changes - **Added `Accept-Ranges: bytes` header** to all file responses - **Created `parseRangeHeader` utility** for parsing Range headers using `range-parser` package - **Enhanced `streamFile` function** to support byte range streaming via `fs.createReadStream` options - **Added integration tests** covering various range request scenarios ## Technical Details - Uses `range-parser` library for RFC 7233 compliant parsing - Supports single byte ranges (e.g., `bytes=0-1023`) - Handles open-ended ranges (e.g., `bytes=1024-`) - Handles suffix ranges (e.g., `bytes=-512`) - Multi-range requests return first range only (standard simplification) ## Testing Added comprehensive integration test suite covering: - Full file requests with Accept-Ranges header - Partial content requests (206 responses) - Invalid range handling (416 responses) - Response body size verification - Edge cases (out-of-bounds, malformed headers) ### Before https://github.com/user-attachments/assets/065060ae-35db-4c3d-bc72-cfb976b57349 ### After https://github.com/user-attachments/assets/b70caa49-e055-47b2-87f8-31f02a42c86a --- packages/payload/package.json | 2 + .../payload/src/uploads/endpoints/getFile.ts | 47 +++++++- .../src/uploads/fetchAPI-stream-file/index.ts | 10 +- .../payload/src/uploads/parseRangeHeader.ts | 60 ++++++++++ pnpm-lock.yaml | 6 + test/uploads/int.spec.ts | 110 ++++++++++++++++++ 6 files changed, 230 insertions(+), 5 deletions(-) create mode 100644 packages/payload/src/uploads/parseRangeHeader.ts diff --git a/packages/payload/package.json b/packages/payload/package.json index c1541cc19e7..0d7c1af0010 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -114,6 +114,7 @@ "pino-pretty": "13.1.2", "pluralize": "8.0.0", "qs-esm": "7.0.2", + "range-parser": "1.2.1", "sanitize-filename": "1.6.3", "scmp": "2.1.0", "ts-essentials": "10.0.3", @@ -130,6 +131,7 @@ "@types/minimist": "1.2.2", "@types/nodemailer": "7.0.2", "@types/pluralize": "0.0.33", + "@types/range-parser": "1.2.7", "@types/uuid": "10.0.0", "@types/ws": "^8.5.10", "copyfiles": "2.4.1", diff --git a/packages/payload/src/uploads/endpoints/getFile.ts b/packages/payload/src/uploads/endpoints/getFile.ts index 6b6d63edb35..658cb2c3b54 100644 --- a/packages/payload/src/uploads/endpoints/getFile.ts +++ b/packages/payload/src/uploads/endpoints/getFile.ts @@ -11,6 +11,7 @@ import { APIError } from '../../errors/APIError.js' import { checkFileAccess } from '../../uploads/checkFileAccess.js' import { streamFile } from '../../uploads/fetchAPI-stream-file/index.js' import { getFileTypeFallback } from '../../uploads/getFileTypeFallback.js' +import { parseRangeHeader } from '../../uploads/parseRangeHeader.js' import { getRequestCollection } from '../../utilities/getRequestEntity.js' import { headersWithCors } from '../../utilities/headersWithCors.js' @@ -94,7 +95,6 @@ export const getFileHandler: PayloadHandler = async (req) => { throw err } - const data = streamFile(filePath) const fileTypeResult = (await fileTypeFromFile(filePath)) || getFileTypeFallback(filePath) let mimeType = fileTypeResult.mime @@ -102,9 +102,50 @@ export const getFileHandler: PayloadHandler = async (req) => { mimeType = 'image/svg+xml' } + // Parse Range header for byte range requests + const rangeHeader = req.headers.get('range') + const rangeResult = parseRangeHeader({ + fileSize: stats.size, + rangeHeader, + }) + + if (rangeResult.type === 'invalid') { + let headers = new Headers() + headers.set('Content-Range', `bytes */${stats.size}`) + headers = collection.config.upload?.modifyResponseHeaders + ? collection.config.upload.modifyResponseHeaders({ headers }) || headers + : headers + + return new Response(null, { + headers: headersWithCors({ + headers, + req, + }), + status: httpStatus.REQUESTED_RANGE_NOT_SATISFIABLE, + }) + } + let headers = new Headers() headers.set('Content-Type', mimeType) - headers.set('Content-Length', stats.size + '') + headers.set('Accept-Ranges', 'bytes') + + let data: ReadableStream + let status: number + const isPartial = rangeResult.type === 'partial' + const range = rangeResult.range + + if (isPartial && range) { + const contentLength = range.end - range.start + 1 + headers.set('Content-Length', String(contentLength)) + headers.set('Content-Range', `bytes ${range.start}-${range.end}/${stats.size}`) + data = streamFile({ filePath, options: { end: range.end, start: range.start } }) + status = httpStatus.PARTIAL_CONTENT + } else { + headers.set('Content-Length', String(stats.size)) + data = streamFile({ filePath }) + status = httpStatus.OK + } + headers = collection.config.upload?.modifyResponseHeaders ? collection.config.upload.modifyResponseHeaders({ headers }) || headers : headers @@ -114,6 +155,6 @@ export const getFileHandler: PayloadHandler = async (req) => { headers, req, }), - status: httpStatus.OK, + status, }) } diff --git a/packages/payload/src/uploads/fetchAPI-stream-file/index.ts b/packages/payload/src/uploads/fetchAPI-stream-file/index.ts index 4745b6177b5..3f4cd7640cd 100644 --- a/packages/payload/src/uploads/fetchAPI-stream-file/index.ts +++ b/packages/payload/src/uploads/fetchAPI-stream-file/index.ts @@ -19,8 +19,14 @@ export async function* nodeStreamToIterator(stream: fs.ReadStream) { } } -export function streamFile(path: string): ReadableStream { - const nodeStream = fs.createReadStream(path) +export function streamFile({ + filePath, + options, +}: { + filePath: string + options?: { end?: number; start?: number } +}): ReadableStream { + const nodeStream = fs.createReadStream(filePath, options) const data: ReadableStream = iteratorToStream(nodeStreamToIterator(nodeStream)) return data } diff --git a/packages/payload/src/uploads/parseRangeHeader.ts b/packages/payload/src/uploads/parseRangeHeader.ts new file mode 100644 index 00000000000..8e50a0df3a6 --- /dev/null +++ b/packages/payload/src/uploads/parseRangeHeader.ts @@ -0,0 +1,60 @@ +import parseRange from 'range-parser' + +export type ByteRange = { + end: number + start: number +} + +export type ParseRangeResult = + | { range: ByteRange; type: 'partial' } + | { range: null; type: 'full' } + | { range: null; type: 'invalid' } + +/** + * Parses HTTP Range header according to RFC 7233 + * + * @returns Result object indicating whether to serve full file, partial content, or invalid range + */ +export function parseRangeHeader({ + fileSize, + rangeHeader, +}: { + fileSize: number + rangeHeader: null | string +}): ParseRangeResult { + // No Range header - serve full file + if (!rangeHeader) { + return { type: 'full', range: null } + } + + const result = parseRange(fileSize, rangeHeader) + + // Invalid range syntax or unsatisfiable range + if (result === -1 || result === -2) { + return { type: 'invalid', range: null } + } + + // Must be bytes range type + if (result.type !== 'bytes') { + return { type: 'invalid', range: null } + } + + // Multi-range requests: use first range only (standard simplification) + if (result.length === 0) { + return { type: 'invalid', range: null } + } + + const range = result[0] + + if (range) { + return { + type: 'partial', + range: { + end: range.end, + start: range.start, + }, + } + } + + return { type: 'invalid', range: null } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc8c92a6c8c..35e1108593a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -944,6 +944,9 @@ importers: qs-esm: specifier: 7.0.2 version: 7.0.2 + range-parser: + specifier: 1.2.1 + version: 1.2.1 sanitize-filename: specifier: 1.6.3 version: 1.6.3 @@ -987,6 +990,9 @@ importers: '@types/pluralize': specifier: 0.0.33 version: 0.0.33 + '@types/range-parser': + specifier: 1.2.7 + version: 1.2.7 '@types/uuid': specifier: 10.0.0 version: 10.0.0 diff --git a/test/uploads/int.spec.ts b/test/uploads/int.spec.ts index be9b16d3fb2..2e8f251d67c 100644 --- a/test/uploads/int.spec.ts +++ b/test/uploads/int.spec.ts @@ -1285,6 +1285,116 @@ describe('Collections - Uploads', () => { expect(await fileExists(path.join(expectedPath, duplicatedDoc.filename))).toBe(true) }) }) + + describe('HTTP Range Requests', () => { + let uploadedDoc: Media + let uploadedFilename: string + let fileSize: number + + beforeAll(async () => { + // Upload a test file for range request testing + const filePath = path.join(dirname, './audio.mp3') + const file = await getFileByPath(filePath) + + uploadedDoc = (await payload.create({ + collection: mediaSlug, + data: {}, + file, + })) as unknown as Media + + uploadedFilename = uploadedDoc.filename + const stats = await stat(filePath) + fileSize = stats.size + }) + + it('should return Accept-Ranges header on full file request', async () => { + const response = await restClient.GET(`/${mediaSlug}/file/${uploadedFilename}`) + + expect(response.status).toBe(200) + expect(response.headers.get('Accept-Ranges')).toBe('bytes') + expect(response.headers.get('Content-Length')).toBe(String(fileSize)) + }) + + it('should handle range request with single byte range', async () => { + const response = await restClient.GET(`/${mediaSlug}/file/${uploadedFilename}`, { + headers: { Range: 'bytes=0-1023' }, + }) + + expect(response.status).toBe(206) + expect(response.headers.get('Content-Range')).toBe(`bytes 0-1023/${fileSize}`) + expect(response.headers.get('Content-Length')).toBe('1024') + expect(response.headers.get('Accept-Ranges')).toBe('bytes') + + const arrayBuffer = await response.arrayBuffer() + expect(arrayBuffer.byteLength).toBe(1024) + }) + + it('should handle range request with open-ended range', async () => { + const response = await restClient.GET(`/${mediaSlug}/file/${uploadedFilename}`, { + headers: { Range: 'bytes=1024-' }, + }) + + expect(response.status).toBe(206) + expect(response.headers.get('Content-Range')).toBe(`bytes 1024-${fileSize - 1}/${fileSize}`) + expect(response.headers.get('Content-Length')).toBe(String(fileSize - 1024)) + + const arrayBuffer = await response.arrayBuffer() + expect(arrayBuffer.byteLength).toBe(fileSize - 1024) + }) + + it('should handle range request for suffix bytes', async () => { + const response = await restClient.GET(`/${mediaSlug}/file/${uploadedFilename}`, { + headers: { Range: 'bytes=-512' }, + }) + + expect(response.status).toBe(206) + expect(response.headers.get('Content-Range')).toBe( + `bytes ${fileSize - 512}-${fileSize - 1}/${fileSize}`, + ) + expect(response.headers.get('Content-Length')).toBe('512') + + const arrayBuffer = await response.arrayBuffer() + expect(arrayBuffer.byteLength).toBe(512) + }) + + it('should return 416 for invalid range (start > file size)', async () => { + const response = await restClient.GET(`/${mediaSlug}/file/${uploadedFilename}`, { + headers: { Range: `bytes=${fileSize + 1000}-` }, + }) + + expect(response.status).toBe(416) + expect(response.headers.get('Content-Range')).toBe(`bytes */${fileSize}`) + }) + + it('should handle multi-range requests by returning first range', async () => { + const response = await restClient.GET(`/${mediaSlug}/file/${uploadedFilename}`, { + headers: { Range: 'bytes=0-1023,2048-3071' }, + }) + + expect(response.status).toBe(206) + expect(response.headers.get('Content-Range')).toBe(`bytes 0-1023/${fileSize}`) + expect(response.headers.get('Content-Length')).toBe('1024') + + const arrayBuffer = await response.arrayBuffer() + expect(arrayBuffer.byteLength).toBe(1024) + }) + + it('should handle range at end of file', async () => { + const lastByte = fileSize - 1 + const response = await restClient.GET(`/${mediaSlug}/file/${uploadedFilename}`, { + headers: { Range: `bytes=${lastByte}-${lastByte}` }, + }) + + expect(response.status).toBe(206) + expect(response.headers.get('Content-Range')).toBe( + `bytes ${lastByte}-${lastByte}/${fileSize}`, + ) + expect(response.headers.get('Content-Length')).toBe('1') + + const arrayBuffer = await response.arrayBuffer() + expect(arrayBuffer.byteLength).toBe(1) + }) + }) }) async function fileExists(fileName: string): Promise { From 1487f30fe9ac39cf9ab23bded441c37abe4bb71d Mon Sep 17 00:00:00 2001 From: Jarrod Flesch <30633324+JarrodMFlesch@users.noreply.github.com> Date: Tue, 16 Dec 2025 10:46:42 -0500 Subject: [PATCH 17/67] test: multi-tenant login tiles (#14940) Just adds buttons for logging in with different types of users in the plugin-multi-tenant test config. CleanShot 2025-12-16 at 09 31 49 --- .../components/BeforeLogin/index.scss | 67 +++++++++++++ .../components/BeforeLogin/index.tsx | 97 +++++++++++++++++++ test/plugin-multi-tenant/config.ts | 1 + test/plugin-multi-tenant/credentials.ts | 4 + test/plugin-multi-tenant/payload-types.ts | 1 + test/plugin-multi-tenant/seed/index.ts | 3 +- 6 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 test/plugin-multi-tenant/components/BeforeLogin/index.scss create mode 100644 test/plugin-multi-tenant/components/BeforeLogin/index.tsx diff --git a/test/plugin-multi-tenant/components/BeforeLogin/index.scss b/test/plugin-multi-tenant/components/BeforeLogin/index.scss new file mode 100644 index 00000000000..3f244d904b2 --- /dev/null +++ b/test/plugin-multi-tenant/components/BeforeLogin/index.scss @@ -0,0 +1,67 @@ +.before-login { + margin-bottom: calc(var(--base) * 1.5); + + &__title { + margin-bottom: calc(var(--base) / 2); + font-size: 1.1rem; + font-weight: 600; + color: var(--theme-elevation-800); + } + + &__description { + margin-bottom: var(--base); + font-size: 0.9rem; + color: var(--theme-elevation-600); + } + + &__buttons { + display: flex; + flex-direction: column; + gap: calc(var(--base) * 0.75); + } + + &__button { + padding: calc(var(--base) * 0.5) calc(var(--base) * 0.75); + border: 1px solid var(--theme-elevation-150); + border-radius: 4px; + background-color: var(--theme-elevation-0); + cursor: pointer; + text-align: left; + transition: all 0.2s; + + &:hover:not(:disabled) { + background-color: var(--theme-success-50); + border-color: var(--theme-success-250); + } + + &:disabled { + cursor: not-allowed; + opacity: 0.5; + } + + &--loading { + background-color: var(--theme-elevation-50); + } + } + + &__button-name { + font-weight: 600; + margin-bottom: calc(var(--base) / 4); + color: var(--theme-elevation-800); + } + + &__button-details { + font-size: 0.85rem; + color: var(--theme-elevation-600); + } + + &__error { + margin-top: var(--base); + padding: calc(var(--base) * 0.75); + background-color: var(--theme-error-50); + border: 1px solid var(--theme-error-200); + border-radius: 4px; + color: var(--theme-error-600); + font-size: 0.9rem; + } +} diff --git a/test/plugin-multi-tenant/components/BeforeLogin/index.tsx b/test/plugin-multi-tenant/components/BeforeLogin/index.tsx new file mode 100644 index 00000000000..455f601c122 --- /dev/null +++ b/test/plugin-multi-tenant/components/BeforeLogin/index.tsx @@ -0,0 +1,97 @@ +'use client' + +import type { PayloadClientReactComponent, SanitizedConfig } from 'payload' + +import { useAuth, useRouteCache } from '@payloadcms/ui' +import React, { useState } from 'react' + +import { credentials } from '../../credentials.js' +import './index.scss' + +const baseClass = 'before-login' + +const testUsers = [ + { + name: 'Admin (All Tenants)', + ...credentials.admin, + }, + { + name: 'Blue Dog User', + ...credentials.blueDog, + }, + { + name: 'Multi-Tenant Owner', + ...credentials.owner, + }, + { + name: 'Steel Cat User', + ...credentials.steelCat, + }, +] + +export const BeforeLogin: PayloadClientReactComponent< + SanitizedConfig['admin']['components']['beforeLogin'][0] +> = () => { + const { setUser } = useAuth() + const [loading, setLoading] = useState(null) + const [error, setError] = useState(null) + const { clearRouteCache } = useRouteCache() + + const login = React.useCallback( + async (credentials: { email: string; password: string }) => { + const response = await fetch('/api/users/login', { + body: JSON.stringify(credentials), + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', + }) + + if (!response.ok) { + throw new Error(`Login failed with status ${response.status}`) + } + + const data = await response.json() + setUser(data) + clearRouteCache() + }, + [setUser, clearRouteCache], + ) + + const handleQuickLogin = async (email: string, password: string) => { + setLoading(email) + setError(null) + try { + await login({ email, password }) + } catch (err) { + setError(err instanceof Error ? err.message : 'Login failed') + setLoading(null) + } + } + + return ( +
+

Multi-Tenant Test Users

+

+ Quick login for testing different tenant access patterns +

+
+ {testUsers.map((user) => ( + + ))} +
+ {error &&
{error}
} +
+ ) +} diff --git a/test/plugin-multi-tenant/config.ts b/test/plugin-multi-tenant/config.ts index 638c2dae824..a2f950d6220 100644 --- a/test/plugin-multi-tenant/config.ts +++ b/test/plugin-multi-tenant/config.ts @@ -25,6 +25,7 @@ export default buildConfigWithDefaults({ baseDir: path.resolve(dirname), }, components: { + beforeLogin: ['/components/BeforeLogin/index.js#BeforeLogin'], graphics: { Logo: '/components/Logo/index.js#Logo', Icon: '/components/Icon/index.js#Icon', diff --git a/test/plugin-multi-tenant/credentials.ts b/test/plugin-multi-tenant/credentials.ts index 9e546c8cfd2..2a227f78a6a 100644 --- a/test/plugin-multi-tenant/credentials.ts +++ b/test/plugin-multi-tenant/credentials.ts @@ -11,4 +11,8 @@ export const credentials = { email: 'owner@anchorAndBlueDog.com', password: 'test', }, + steelCat: { + email: 'huel@steel-cat.com', + password: 'test', + }, } as const diff --git a/test/plugin-multi-tenant/payload-types.ts b/test/plugin-multi-tenant/payload-types.ts index 84729c9057f..469b797f46d 100644 --- a/test/plugin-multi-tenant/payload-types.ts +++ b/test/plugin-multi-tenant/payload-types.ts @@ -98,6 +98,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: ('false' | 'none' | 'null') | false | null | ('en' | 'es' | 'fr') | ('en' | 'es' | 'fr')[]; globals: {}; globalsSelect: {}; locale: 'en' | 'es' | 'fr'; diff --git a/test/plugin-multi-tenant/seed/index.ts b/test/plugin-multi-tenant/seed/index.ts index e77018effe8..ff0f87d5494 100644 --- a/test/plugin-multi-tenant/seed/index.ts +++ b/test/plugin-multi-tenant/seed/index.ts @@ -239,8 +239,7 @@ export const seed: Config['onInit'] = async (payload) => { await payload.create({ collection: usersSlug, data: { - email: 'huel@steel-cat.com', - password: 'test', + ...credentials.steelCat, roles: ['user'], tenants: [ { From 25b327d0451b1d9e0301842a5b12dc42ad580c60 Mon Sep 17 00:00:00 2001 From: Jarrod Flesch <30633324+JarrodMFlesch@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:54:14 -0500 Subject: [PATCH 18/67] fix(plugin-multi-tenant): relationTo arrays inflating filterOptions where query size (#14944) Before the plugin was looping over relationTo arrays and would build up duplicate tenant queries. Now it just ensures that there is at lease 1 tenant enabled collection and adds a single tenant constraint to the filterOptions. Helpful to note that the relationships are populated 1 at a time and the filterOptions receives `relationTo` arg, the injected filter checks to see if the requested relation is a tenant enabled collection also before applying the constraint. --- .../src/utilities/addFilterOptionsToFields.ts | 35 ++++----- .../openRelationshipFieldDrawer.ts | 59 +++++++++++++++ .../collections/MenuItems.ts | 10 ++- .../collections/Relationships.ts | 6 +- test/plugin-multi-tenant/config.ts | 23 +++++- test/plugin-multi-tenant/e2e.spec.ts | 73 +++++++++++++++++++ test/plugin-multi-tenant/payload-types.ts | 63 +++++++++++++--- test/plugin-multi-tenant/shared.ts | 4 + 8 files changed, 237 insertions(+), 36 deletions(-) create mode 100644 test/helpers/e2e/fields/relationship/openRelationshipFieldDrawer.ts diff --git a/packages/plugin-multi-tenant/src/utilities/addFilterOptionsToFields.ts b/packages/plugin-multi-tenant/src/utilities/addFilterOptionsToFields.ts index 2b8f054ec19..752b6b67c04 100644 --- a/packages/plugin-multi-tenant/src/utilities/addFilterOptionsToFields.ts +++ b/packages/plugin-multi-tenant/src/utilities/addFilterOptionsToFields.ts @@ -36,6 +36,7 @@ export function addFilterOptionsToFields({ for (const field of fields) { let newField: Field = { ...field } if (newField.type === 'relationship') { + let hasTenantRelationsips = false /** * Adjusts relationship fields to filter by tenant * and ensures relationTo cannot be a tenant global collection @@ -47,15 +48,7 @@ export function addFilterOptionsToFields({ ) } if (tenantEnabledCollectionSlugs.includes(newField.relationTo)) { - newField = addFilter({ - field: newField, - tenantEnabledCollectionSlugs, - tenantFieldName, - tenantsArrayFieldName, - tenantsArrayTenantFieldName, - tenantsCollectionSlug, - userHasAccessToAllTenants, - }) + hasTenantRelationsips = true } } else { for (const relationTo of newField.relationTo) { @@ -65,18 +58,22 @@ export function addFilterOptionsToFields({ ) } if (tenantEnabledCollectionSlugs.includes(relationTo)) { - newField = addFilter({ - field: newField as RelationshipField, - tenantEnabledCollectionSlugs, - tenantFieldName, - tenantsArrayFieldName, - tenantsArrayTenantFieldName, - tenantsCollectionSlug, - userHasAccessToAllTenants, - }) + hasTenantRelationsips = true } } } + + if (hasTenantRelationsips) { + newField = addRelationshipFilter({ + field: newField as RelationshipField, + tenantEnabledCollectionSlugs, + tenantFieldName, + tenantsArrayFieldName, + tenantsArrayTenantFieldName, + tenantsCollectionSlug, + userHasAccessToAllTenants, + }) + } } if ( @@ -175,7 +172,7 @@ type AddFilterArgs = { MultiTenantPluginConfig >['userHasAccessToAllTenants'] } -function addFilter({ +function addRelationshipFilter({ field, tenantEnabledCollectionSlugs, tenantFieldName, diff --git a/test/helpers/e2e/fields/relationship/openRelationshipFieldDrawer.ts b/test/helpers/e2e/fields/relationship/openRelationshipFieldDrawer.ts new file mode 100644 index 00000000000..735f41d15fc --- /dev/null +++ b/test/helpers/e2e/fields/relationship/openRelationshipFieldDrawer.ts @@ -0,0 +1,59 @@ +import type { Page } from '@playwright/test' + +import { expect } from '@playwright/test' +import { wait } from 'payload/shared' + +import { selectInput } from '../../selectInput.js' + +/** + * Opens a list drawer for a relationship field with appearance="drawer" + * and optionally selects a specific collection type for polymorphic relationships. + * + * @param page - Playwright Page object + * @param fieldName - Name of the relationship field (e.g., 'relationship', 'relationshipHasMany') + * @param selectRelation - Optional: Collection slug to select for polymorphic relationships (e.g., 'posts', 'users') + * + * @example + * // Open list drawer for a non-polymorphic relationship + * await openRelationshipFieldDrawer({ page, fieldName: 'relationship' }) + * + * @example + * // Open list drawer and select a specific collection for polymorphic relationship + * await openRelationshipFieldDrawer({ + * page, + * fieldName: 'polymorphicRelationship', + * selectRelation: 'tenants' + * }) + */ +export async function openRelationshipFieldDrawer({ + fieldName, + page, + selectRelation, +}: { + fieldName: string + page: Page + selectRelation?: string +}): Promise { + await wait(300) + + // Click the relationship field to open the list drawer + const relationshipField = page.locator(`#field-${fieldName}`) + await relationshipField.click() + + // Wait for list drawer to be visible + const listDrawerContent = page.locator('.list-drawer').locator('.drawer__content') + await expect(listDrawerContent).toBeVisible() + + // If a specific relation type should be selected (for polymorphic relationships) + if (selectRelation) { + const relationToSelector = page.locator('.list-header__select-collection') + await expect(relationToSelector).toBeVisible() + + await selectInput({ + selectLocator: relationToSelector, + option: selectRelation, + multiSelect: false, + selectType: 'select', + }) + } +} diff --git a/test/plugin-multi-tenant/collections/MenuItems.ts b/test/plugin-multi-tenant/collections/MenuItems.ts index 92bd55c50f6..a02809c17db 100644 --- a/test/plugin-multi-tenant/collections/MenuItems.ts +++ b/test/plugin-multi-tenant/collections/MenuItems.ts @@ -2,7 +2,7 @@ import type { Access, CollectionConfig, Where } from 'payload' import { getUserTenantIDs } from '@payloadcms/plugin-multi-tenant/utilities' -import { menuItemsSlug } from '../shared.js' +import { menuItemsSlug, notTenantedSlug, relationshipsSlug } from '../shared.js' const collectionTenantReadAccess: Access = ({ req }) => { // admins can access all tenants @@ -97,5 +97,13 @@ export const MenuItems: CollectionConfig = { name: 'content', type: 'richText', }, + { + name: 'polymorphicRelationship', + type: 'relationship', + relationTo: [relationshipsSlug, menuItemsSlug, notTenantedSlug], + admin: { + appearance: 'drawer', + }, + }, ], } diff --git a/test/plugin-multi-tenant/collections/Relationships.ts b/test/plugin-multi-tenant/collections/Relationships.ts index 8097d8b74fa..78a9ab67cda 100644 --- a/test/plugin-multi-tenant/collections/Relationships.ts +++ b/test/plugin-multi-tenant/collections/Relationships.ts @@ -1,7 +1,9 @@ import type { CollectionConfig } from 'payload' +import { relationshipsSlug } from '../shared.js' + export const Relationships: CollectionConfig = { - slug: 'relationships', + slug: relationshipsSlug, admin: { useAsTitle: 'title', group: 'Tenant Collections', @@ -15,7 +17,7 @@ export const Relationships: CollectionConfig = { { name: 'relationship', type: 'relationship', - relationTo: 'relationships', + relationTo: relationshipsSlug, }, ], } diff --git a/test/plugin-multi-tenant/config.ts b/test/plugin-multi-tenant/config.ts index a2f950d6220..3fa13f0ca2d 100644 --- a/test/plugin-multi-tenant/config.ts +++ b/test/plugin-multi-tenant/config.ts @@ -15,10 +15,29 @@ import { Relationships } from './collections/Relationships.js' import { Tenants } from './collections/Tenants.js' import { Users } from './collections/Users/index.js' import { seed } from './seed/index.js' -import { autosaveGlobalSlug, menuItemsSlug, menuSlug } from './shared.js' +import { autosaveGlobalSlug, menuItemsSlug, menuSlug, notTenantedSlug } from './shared.js' export default buildConfigWithDefaults({ - collections: [Tenants, Users, MenuItems, Menu, AutosaveGlobal, Relationships], + collections: [ + Tenants, + Users, + MenuItems, + Menu, + AutosaveGlobal, + Relationships, + { + slug: notTenantedSlug, + admin: { + useAsTitle: 'name', + }, + fields: [ + { + name: 'name', + type: 'text', + }, + ], + }, + ], admin: { autoLogin: false, importMap: { diff --git a/test/plugin-multi-tenant/e2e.spec.ts b/test/plugin-multi-tenant/e2e.spec.ts index b52d82f939b..584307a0b23 100644 --- a/test/plugin-multi-tenant/e2e.spec.ts +++ b/test/plugin-multi-tenant/e2e.spec.ts @@ -17,6 +17,7 @@ import { } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { loginClientSide } from '../helpers/e2e/auth/login.js' +import { openRelationshipFieldDrawer } from '../helpers/e2e/fields/relationship/openRelationshipFieldDrawer.js' import { goToListDoc } from '../helpers/e2e/goToListDoc.js' import { clearSelectInput, @@ -516,6 +517,78 @@ test.describe('Multi Tenant', () => { }) }) + test.describe('Polymorphic Relationships', () => { + test('should not duplicate tenant constraints in polymorphic relationship queries', async () => { + await loginClientSide({ + data: credentials.admin, + page, + serverURL, + }) + + // Capture render-list server action requests + const renderListRequests: Array<{ + payload: any[] + url: string + }> = [] + + page.on('request', (request) => { + // Check for server action POST requests + if ( + request.method() === 'POST' && + request.url().includes(`/admin/collections/${menuItemsSlug}`) + ) { + const postData = request.postData() + if (postData) { + try { + const parsedPayload = JSON.parse(postData) + // Check if this is a render-list action + if (Array.isArray(parsedPayload) && parsedPayload[0]?.name === 'render-list') { + renderListRequests.push({ + url: request.url(), + payload: parsedPayload, + }) + } + } catch (e) { + // Ignore parse errors + } + } + } + }) + + // Navigate to existing menu item + await page.goto(menuItemsURL.list) + await clearTenantFilter({ page }) + + await goToListDoc({ + cellClass: '.cell-name', + page, + textToMatch: 'Spicy Mac', + urlUtil: menuItemsURL, + }) + + await openRelationshipFieldDrawer({ + page, + fieldName: 'polymorphicRelationship', + selectRelation: 'Relationship', // select a tenant-enabled collection + }) + + await expect.poll(() => renderListRequests.length).toBeGreaterThan(0) + + // Check the query.where clause for tenant constraint duplication + for (const request of renderListRequests) { + const renderListAction = request.payload[0] + await expect.poll(() => renderListAction.name).toBe('render-list') + await expect.poll(() => renderListAction.args).toBeDefined() + await expect.poll(() => renderListAction.args.query).toBeDefined() + + const whereString = JSON.stringify(renderListAction.args.query.where) + const tenantMatches = whereString.match(/"tenant":/g)?.length + + await expect.poll(() => tenantMatches).toEqual(1) + } + }) + }) + test.describe('Tenant Selector', () => { test('should populate tenant selector on login', async () => { await loginClientSide({ diff --git a/test/plugin-multi-tenant/payload-types.ts b/test/plugin-multi-tenant/payload-types.ts index 469b797f46d..25a4757f0f1 100644 --- a/test/plugin-multi-tenant/payload-types.ts +++ b/test/plugin-multi-tenant/payload-types.ts @@ -73,6 +73,7 @@ export interface Config { 'food-menu': FoodMenu; 'autosave-global': AutosaveGlobal; relationships: Relationship; + notTenanted: NotTenanted; 'payload-kv': PayloadKv; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -90,6 +91,7 @@ export interface Config { 'food-menu': FoodMenuSelect | FoodMenuSelect; 'autosave-global': AutosaveGlobalSelect | AutosaveGlobalSelect; relationships: RelationshipsSelect | RelationshipsSelect; + notTenanted: NotTenantedSelect | NotTenantedSelect; 'payload-kv': PayloadKvSelect | PayloadKvSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -201,6 +203,41 @@ export interface FoodItem { }; [k: string]: unknown; } | null; + polymorphicRelationship?: + | ({ + relationTo: 'relationships'; + value: string | Relationship; + } | null) + | ({ + relationTo: 'food-items'; + value: string | FoodItem; + } | null) + | ({ + relationTo: 'notTenanted'; + value: string | NotTenanted; + } | null); + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "relationships". + */ +export interface Relationship { + id: string; + tenant?: (string | null) | Tenant; + title: string; + relationship?: (string | null) | Relationship; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "notTenanted". + */ +export interface NotTenanted { + id: string; + name?: string | null; updatedAt: string; createdAt: string; } @@ -239,18 +276,6 @@ export interface AutosaveGlobal { createdAt: string; _status?: ('draft' | 'published') | null; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "relationships". - */ -export interface Relationship { - id: string; - tenant?: (string | null) | Tenant; - title: string; - relationship?: (string | null) | Relationship; - updatedAt: string; - createdAt: string; -} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-kv". @@ -298,6 +323,10 @@ export interface PayloadLockedDocument { | ({ relationTo: 'relationships'; value: string | Relationship; + } | null) + | ({ + relationTo: 'notTenanted'; + value: string | NotTenanted; } | null); globalSlug?: string | null; user: { @@ -392,6 +421,7 @@ export interface FoodItemsSelect { name?: T; localizedName?: T; content?: T; + polymorphicRelationship?: T; updatedAt?: T; createdAt?: T; } @@ -436,6 +466,15 @@ export interface RelationshipsSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "notTenanted_select". + */ +export interface NotTenantedSelect { + name?: T; + updatedAt?: T; + createdAt?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-kv_select". diff --git a/test/plugin-multi-tenant/shared.ts b/test/plugin-multi-tenant/shared.ts index bcfdfa3269e..7c5b41a6b42 100644 --- a/test/plugin-multi-tenant/shared.ts +++ b/test/plugin-multi-tenant/shared.ts @@ -7,3 +7,7 @@ export const menuItemsSlug = 'food-items' export const menuSlug = 'food-menu' export const autosaveGlobalSlug = 'autosave-global' + +export const relationshipsSlug = 'relationships' + +export const notTenantedSlug = 'notTenanted' From 0ea7c695c17303cfeab4a5ad5476438c3a80236f Mon Sep 17 00:00:00 2001 From: Patrik <35232443+PatrikKozak@users.noreply.github.com> Date: Tue, 16 Dec 2025 17:11:56 -0500 Subject: [PATCH 19/67] fix(next): status component incorrectly shows as published status on new documents saved as drafts when readVersions permissions are false (#14950) ### What? Fixes incorrect `status` display when creating and saving new draft documents in collections where users don't have readVersions permission. ### Why? The `getVersions` function was incorrectly assuming any document with an ID is published, causing the Status component to show "Published" for newly created drafts. This happens when `readVersions` permission is disabled because the code takes an early return path that doesn't query the versions collection. ### How? - Changed the early return logic in `getVersions.ts` to check the document's `_status` field directly - Returns `hasPublishedDoc = false` only when `_status === 'draft'`, otherwise `true` --- .../next/src/views/Document/getVersions.ts | 3 +- .../collections/DraftsNoReadVersions.ts | 30 +++++++++++ test/versions/config.ts | 2 + test/versions/e2e.spec.ts | 51 +++++++++++++++++++ test/versions/payload-types.ts | 30 +++++++++++ test/versions/slugs.ts | 2 + 6 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 test/versions/collections/DraftsNoReadVersions.ts diff --git a/packages/next/src/views/Document/getVersions.ts b/packages/next/src/views/Document/getVersions.ts index 9bcda8f6450..27069784dc7 100644 --- a/packages/next/src/views/Document/getVersions.ts +++ b/packages/next/src/views/Document/getVersions.ts @@ -60,7 +60,8 @@ export const getVersions = async ({ const shouldFetchVersions = Boolean(versionsConfig && docPermissions?.readVersions) if (!shouldFetchVersions) { - const hasPublishedDoc = Boolean((collectionConfig && id) || globalConfig) + // Without readVersions permission, determine published status from the _status field + const hasPublishedDoc = doc?._status !== 'draft' return { hasPublishedDoc, diff --git a/test/versions/collections/DraftsNoReadVersions.ts b/test/versions/collections/DraftsNoReadVersions.ts new file mode 100644 index 00000000000..cf1d026bcf4 --- /dev/null +++ b/test/versions/collections/DraftsNoReadVersions.ts @@ -0,0 +1,30 @@ +import type { CollectionConfig } from 'payload' + +import { draftsNoReadVersionsSlug } from '../slugs.js' + +const DraftsNoReadVersions: CollectionConfig = { + slug: draftsNoReadVersionsSlug, + access: { + readVersions: () => false, + }, + admin: { + defaultColumns: ['title', 'createdAt', '_status'], + useAsTitle: 'title', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'description', + type: 'textarea', + }, + ], + versions: { + drafts: true, + }, +} + +export default DraftsNoReadVersions diff --git a/test/versions/config.ts b/test/versions/config.ts index cde27db4c23..2b5aede3237 100644 --- a/test/versions/config.ts +++ b/test/versions/config.ts @@ -11,6 +11,7 @@ import CustomIDs from './collections/CustomIDs.js' import { Diff } from './collections/Diff/index.js' import DisablePublish from './collections/DisablePublish.js' import DraftPosts from './collections/Drafts.js' +import DraftsNoReadVersions from './collections/DraftsNoReadVersions.js' import DraftWithChangeHook from './collections/DraftsWithChangeHook.js' import DraftWithMax from './collections/DraftsWithMax.js' import DraftsWithValidate from './collections/DraftsWithValidate.js' @@ -47,6 +48,7 @@ export default buildConfigWithDefaults({ AutosaveWithMultiSelectPosts, AutosaveWithDraftValidate, DraftPosts, + DraftsNoReadVersions, DraftWithMax, DraftWithChangeHook, DraftsWithValidate, diff --git a/test/versions/e2e.spec.ts b/test/versions/e2e.spec.ts index 9b693a6d3fa..138a17a4eef 100644 --- a/test/versions/e2e.spec.ts +++ b/test/versions/e2e.spec.ts @@ -63,6 +63,7 @@ import { disablePublishSlug, draftCollectionSlug, draftGlobalSlug, + draftsNoReadVersionsSlug, draftWithChangeHookCollectionSlug, draftWithMaxCollectionSlug, draftWithMaxGlobalSlug, @@ -96,6 +97,7 @@ describe('Versions', () => { let customIDURL: AdminUrlUtil let postURL: AdminUrlUtil let errorOnUnpublishURL: AdminUrlUtil + let draftsNoReadVersionsURL: AdminUrlUtil beforeAll(async ({ browser }, testInfo) => { testInfo.setTimeout(TEST_TIMEOUT_LONG) @@ -134,6 +136,7 @@ describe('Versions', () => { customIDURL = new AdminUrlUtil(serverURL, customIDSlug) postURL = new AdminUrlUtil(serverURL, postCollectionSlug) errorOnUnpublishURL = new AdminUrlUtil(serverURL, errorOnUnpublishSlug) + draftsNoReadVersionsURL = new AdminUrlUtil(serverURL, draftsNoReadVersionsSlug) }) test('collection — should show "has published version" status in list view when draft is saved after publish', async () => { @@ -937,6 +940,54 @@ describe('Versions', () => { expect(scanResults.elementsWithoutIndicators).toBe(0) }) }) + + describe('without readVersions permission', () => { + test('should show Draft status when creating and saving a new draft document', async () => { + await page.goto(draftsNoReadVersionsURL.create) + await page.locator('#field-title').fill('Test Draft Title') + await page.locator('#field-description').fill('Test Draft Description') + + await saveDocAndAssert(page, '#action-save-draft') + + await expect(page.locator('.doc-controls__status .status__value')).toContainText('Draft') + + await expect(page.locator('#action-unpublish')).toBeHidden() + }) + + test('should show Published status after publishing a draft document', async () => { + await page.goto(draftsNoReadVersionsURL.create) + await page.locator('#field-title').fill('Test Publish Title') + await page.locator('#field-description').fill('Test Publish Description') + + await saveDocAndAssert(page, '#action-save-draft') + + await expect(page.locator('.doc-controls__status .status__value')).toContainText('Draft') + + await page.locator('#action-save').click() + + await expect(page.locator('.doc-controls__status .status__value')).toContainText( + 'Published', + ) + + await expect(page.locator('#action-unpublish')).toBeVisible() + }) + + test('should maintain Draft status when saving draft multiple times', async () => { + await page.goto(draftsNoReadVersionsURL.create) + await page.locator('#field-title').fill('Test Multiple Saves') + await page.locator('#field-description').fill('Initial Description') + + await saveDocAndAssert(page, '#action-save-draft') + + await expect(page.locator('.doc-controls__status .status__value')).toContainText('Draft') + + await page.locator('#field-description').fill('Updated Description') + await saveDocAndAssert(page, '#action-save-draft') + + await expect(page.locator('.doc-controls__status .status__value')).toContainText('Draft') + await expect(page.locator('#action-unpublish')).toBeHidden() + }) + }) }) describe('draft globals', () => { diff --git a/test/versions/payload-types.ts b/test/versions/payload-types.ts index 0b819e98afd..91d5d7ab762 100644 --- a/test/versions/payload-types.ts +++ b/test/versions/payload-types.ts @@ -74,6 +74,7 @@ export interface Config { 'autosave-multi-select-posts': AutosaveMultiSelectPost; 'autosave-with-validate-posts': AutosaveWithValidatePost; 'draft-posts': DraftPost; + 'drafts-no-read-versions': DraftsNoReadVersion; 'draft-with-max-posts': DraftWithMaxPost; 'draft-posts-with-change-hook': DraftPostsWithChangeHook; 'draft-with-validate-posts': DraftWithValidatePost; @@ -101,6 +102,7 @@ export interface Config { 'autosave-multi-select-posts': AutosaveMultiSelectPostsSelect | AutosaveMultiSelectPostsSelect; 'autosave-with-validate-posts': AutosaveWithValidatePostsSelect | AutosaveWithValidatePostsSelect; 'draft-posts': DraftPostsSelect | DraftPostsSelect; + 'drafts-no-read-versions': DraftsNoReadVersionsSelect | DraftsNoReadVersionsSelect; 'draft-with-max-posts': DraftWithMaxPostsSelect | DraftWithMaxPostsSelect; 'draft-posts-with-change-hook': DraftPostsWithChangeHookSelect | DraftPostsWithChangeHookSelect; 'draft-with-validate-posts': DraftWithValidatePostsSelect | DraftWithValidatePostsSelect; @@ -122,6 +124,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: ('false' | 'none' | 'null') | false | null | ('en' | 'es' | 'de') | ('en' | 'es' | 'de')[]; globals: { 'autosave-global': AutosaveGlobal; 'autosave-with-draft-button-global': AutosaveWithDraftButtonGlobal; @@ -312,6 +315,18 @@ export interface AutosaveWithValidatePost { createdAt: string; _status?: ('draft' | 'published') | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "drafts-no-read-versions". + */ +export interface DraftsNoReadVersion { + id: string; + title: string; + description?: string | null; + updatedAt: string; + createdAt: string; + _status?: ('draft' | 'published') | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "draft-with-max-posts". @@ -775,6 +790,10 @@ export interface PayloadLockedDocument { relationTo: 'draft-posts'; value: string | DraftPost; } | null) + | ({ + relationTo: 'drafts-no-read-versions'; + value: string | DraftsNoReadVersion; + } | null) | ({ relationTo: 'draft-with-max-posts'; value: string | DraftWithMaxPost; @@ -965,6 +984,17 @@ export interface DraftPostsSelect { createdAt?: T; _status?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "drafts-no-read-versions_select". + */ +export interface DraftsNoReadVersionsSelect { + title?: T; + description?: T; + updatedAt?: T; + createdAt?: T; + _status?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "draft-with-max-posts_select". diff --git a/test/versions/slugs.ts b/test/versions/slugs.ts index 0831f3cd82b..50d741ce3f4 100644 --- a/test/versions/slugs.ts +++ b/test/versions/slugs.ts @@ -9,6 +9,8 @@ export const customIDSlug = 'custom-ids' export const draftCollectionSlug = 'draft-posts' +export const draftsNoReadVersionsSlug = 'drafts-no-read-versions' + export const draftWithValidateCollectionSlug = 'draft-with-validate-posts' export const draftWithMaxCollectionSlug = 'draft-with-max-posts' From d8ee7f8be2d6ee9aafecb2ef6ba1f995988018d9 Mon Sep 17 00:00:00 2001 From: Kendell <1900724+kendelljoseph@users.noreply.github.com> Date: Tue, 16 Dec 2025 17:49:44 -0500 Subject: [PATCH 20/67] feat: adds cursor rules and AGENTS.md to templates (#14889) Adds dev resources to the base template for a better experience when building Payload projects with AI tools like Copilot and Cursor. See more about [AGENTS.md](https://agents.md) # What's Added All templates will now ship with an AGENTS.md and .cursor/rules. 1. `AGENTS.md` - https://agents.md 2. `.cursor/rules/` directory --- docs/plugins/overview.mdx | 2 + templates/_agents/AGENTS.md | 1141 +++++++++++++++++ .../_agents/rules/access-control-advanced.md | 519 ++++++++ templates/_agents/rules/access-control.md | 225 ++++ templates/_agents/rules/adapters.md | 209 +++ templates/_agents/rules/collections.md | 171 +++ templates/_agents/rules/components.md | 794 ++++++++++++ templates/_agents/rules/endpoints.md | 236 ++++ templates/_agents/rules/field-type-guards.md | 230 ++++ templates/_agents/rules/fields.md | 317 +++++ templates/_agents/rules/hooks.md | 175 +++ templates/_agents/rules/payload-overview.md | 126 ++ templates/_agents/rules/plugin-development.md | 323 +++++ templates/_agents/rules/queries.md | 223 ++++ templates/_agents/rules/security-critical.mdc | 122 ++ .../.cursor/rules/access-control-advanced.md | 519 ++++++++ .../blank/.cursor/rules/access-control.md | 225 ++++ templates/blank/.cursor/rules/adapters.md | 209 +++ templates/blank/.cursor/rules/collections.md | 171 +++ templates/blank/.cursor/rules/components.md | 794 ++++++++++++ templates/blank/.cursor/rules/endpoints.md | 236 ++++ .../blank/.cursor/rules/field-type-guards.md | 230 ++++ templates/blank/.cursor/rules/fields.md | 317 +++++ templates/blank/.cursor/rules/hooks.md | 175 +++ .../blank/.cursor/rules/payload-overview.md | 126 ++ .../blank/.cursor/rules/plugin-development.md | 323 +++++ templates/blank/.cursor/rules/queries.md | 223 ++++ .../blank/.cursor/rules/security-critical.mdc | 122 ++ templates/blank/AGENTS.md | 1141 +++++++++++++++++ templates/blank/src/payload-types.ts | 1 + .../.cursor/rules/access-control-advanced.md | 519 ++++++++ .../ecommerce/.cursor/rules/access-control.md | 225 ++++ templates/ecommerce/.cursor/rules/adapters.md | 209 +++ .../ecommerce/.cursor/rules/collections.md | 171 +++ .../ecommerce/.cursor/rules/components.md | 794 ++++++++++++ .../ecommerce/.cursor/rules/endpoints.md | 236 ++++ .../.cursor/rules/field-type-guards.md | 230 ++++ templates/ecommerce/.cursor/rules/fields.md | 317 +++++ templates/ecommerce/.cursor/rules/hooks.md | 175 +++ .../.cursor/rules/payload-overview.md | 126 ++ .../.cursor/rules/plugin-development.md | 323 +++++ templates/ecommerce/.cursor/rules/queries.md | 223 ++++ .../.cursor/rules/security-critical.mdc | 122 ++ templates/ecommerce/AGENTS.md | 1141 +++++++++++++++++ .../src/app/(payload)/admin/importMap.js | 73 +- templates/ecommerce/src/payload-types.ts | 1 + .../.cursor/rules/access-control-advanced.md | 519 ++++++++ .../website/.cursor/rules/access-control.md | 225 ++++ templates/website/.cursor/rules/adapters.md | 209 +++ .../website/.cursor/rules/collections.md | 171 +++ templates/website/.cursor/rules/components.md | 794 ++++++++++++ templates/website/.cursor/rules/endpoints.md | 236 ++++ .../.cursor/rules/field-type-guards.md | 230 ++++ templates/website/.cursor/rules/fields.md | 317 +++++ templates/website/.cursor/rules/hooks.md | 175 +++ .../website/.cursor/rules/payload-overview.md | 126 ++ .../.cursor/rules/plugin-development.md | 323 +++++ templates/website/.cursor/rules/queries.md | 223 ++++ .../.cursor/rules/security-critical.mdc | 122 ++ templates/website/AGENTS.md | 1141 +++++++++++++++++ templates/website/src/payload-types.ts | 1 + .../.cursor/rules/access-control-advanced.md | 519 ++++++++ .../.cursor/rules/access-control.md | 225 ++++ .../.cursor/rules/adapters.md | 209 +++ .../.cursor/rules/collections.md | 171 +++ .../.cursor/rules/components.md | 794 ++++++++++++ .../.cursor/rules/endpoints.md | 236 ++++ .../.cursor/rules/field-type-guards.md | 230 ++++ .../.cursor/rules/fields.md | 317 +++++ .../with-cloudflare-d1/.cursor/rules/hooks.md | 175 +++ .../.cursor/rules/payload-overview.md | 126 ++ .../.cursor/rules/plugin-development.md | 323 +++++ .../.cursor/rules/queries.md | 223 ++++ .../.cursor/rules/security-critical.mdc | 122 ++ templates/with-cloudflare-d1/AGENTS.md | 1141 +++++++++++++++++ templates/with-cloudflare-d1/package.json | 12 +- .../with-cloudflare-d1/src/payload-types.ts | 1 + .../.cursor/rules/access-control-advanced.md | 519 ++++++++ .../.cursor/rules/access-control.md | 225 ++++ .../with-postgres/.cursor/rules/adapters.md | 209 +++ .../.cursor/rules/collections.md | 171 +++ .../with-postgres/.cursor/rules/components.md | 794 ++++++++++++ .../with-postgres/.cursor/rules/endpoints.md | 236 ++++ .../.cursor/rules/field-type-guards.md | 230 ++++ .../with-postgres/.cursor/rules/fields.md | 317 +++++ .../with-postgres/.cursor/rules/hooks.md | 175 +++ .../.cursor/rules/payload-overview.md | 126 ++ .../.cursor/rules/plugin-development.md | 323 +++++ .../with-postgres/.cursor/rules/queries.md | 223 ++++ .../.cursor/rules/security-critical.mdc | 122 ++ templates/with-postgres/AGENTS.md | 1141 +++++++++++++++++ templates/with-postgres/package.json | 10 +- ...tial.json => 20251216_194340_initial.json} | 6 +- ..._initial.ts => 20251216_194340_initial.ts} | 0 .../with-postgres/src/migrations/index.ts | 8 +- templates/with-postgres/src/payload-types.ts | 1 + .../.cursor/rules/access-control-advanced.md | 519 ++++++++ .../.cursor/rules/access-control.md | 225 ++++ .../.cursor/rules/adapters.md | 209 +++ .../.cursor/rules/collections.md | 171 +++ .../.cursor/rules/components.md | 794 ++++++++++++ .../.cursor/rules/endpoints.md | 236 ++++ .../.cursor/rules/field-type-guards.md | 230 ++++ .../.cursor/rules/fields.md | 317 +++++ .../.cursor/rules/hooks.md | 175 +++ .../.cursor/rules/payload-overview.md | 126 ++ .../.cursor/rules/plugin-development.md | 323 +++++ .../.cursor/rules/queries.md | 223 ++++ .../.cursor/rules/security-critical.mdc | 122 ++ templates/with-vercel-mongodb/AGENTS.md | 1141 +++++++++++++++++ templates/with-vercel-mongodb/package.json | 14 +- .../with-vercel-mongodb/src/payload-types.ts | 1 + .../with-vercel-mongodb/src/payload.config.ts | 3 +- .../.cursor/rules/access-control-advanced.md | 519 ++++++++ .../.cursor/rules/access-control.md | 225 ++++ .../.cursor/rules/adapters.md | 209 +++ .../.cursor/rules/collections.md | 171 +++ .../.cursor/rules/components.md | 794 ++++++++++++ .../.cursor/rules/endpoints.md | 236 ++++ .../.cursor/rules/field-type-guards.md | 230 ++++ .../.cursor/rules/fields.md | 317 +++++ .../.cursor/rules/hooks.md | 175 +++ .../.cursor/rules/payload-overview.md | 126 ++ .../.cursor/rules/plugin-development.md | 323 +++++ .../.cursor/rules/queries.md | 223 ++++ .../.cursor/rules/security-critical.mdc | 122 ++ templates/with-vercel-postgres/AGENTS.md | 1141 +++++++++++++++++ templates/with-vercel-postgres/package.json | 14 +- ...tial.json => 20251216_194325_initial.json} | 6 +- ..._initial.ts => 20251216_194325_initial.ts} | 0 .../src/migrations/index.ts | 8 +- .../with-vercel-postgres/src/payload-types.ts | 1 + .../src/payload.config.ts | 3 +- .../.cursor/rules/access-control-advanced.md | 519 ++++++++ .../.cursor/rules/access-control.md | 225 ++++ .../.cursor/rules/adapters.md | 209 +++ .../.cursor/rules/collections.md | 171 +++ .../.cursor/rules/components.md | 794 ++++++++++++ .../.cursor/rules/endpoints.md | 236 ++++ .../.cursor/rules/field-type-guards.md | 230 ++++ .../.cursor/rules/fields.md | 317 +++++ .../.cursor/rules/hooks.md | 175 +++ .../.cursor/rules/payload-overview.md | 126 ++ .../.cursor/rules/plugin-development.md | 323 +++++ .../.cursor/rules/queries.md | 223 ++++ .../.cursor/rules/security-critical.mdc | 122 ++ templates/with-vercel-website/AGENTS.md | 1141 +++++++++++++++++ templates/with-vercel-website/package.json | 28 +- ...tial.json => 20251216_194333_initial.json} | 6 +- ..._initial.ts => 20251216_194333_initial.ts} | 0 .../src/migrations/index.ts | 8 +- .../with-vercel-website/src/payload-types.ts | 1 + .../with-vercel-website/src/payload.config.ts | 4 +- .../src/generate-template-variations.ts | 46 + 154 files changed, 43466 insertions(+), 92 deletions(-) create mode 100644 templates/_agents/AGENTS.md create mode 100644 templates/_agents/rules/access-control-advanced.md create mode 100644 templates/_agents/rules/access-control.md create mode 100644 templates/_agents/rules/adapters.md create mode 100644 templates/_agents/rules/collections.md create mode 100644 templates/_agents/rules/components.md create mode 100644 templates/_agents/rules/endpoints.md create mode 100644 templates/_agents/rules/field-type-guards.md create mode 100644 templates/_agents/rules/fields.md create mode 100644 templates/_agents/rules/hooks.md create mode 100644 templates/_agents/rules/payload-overview.md create mode 100644 templates/_agents/rules/plugin-development.md create mode 100644 templates/_agents/rules/queries.md create mode 100644 templates/_agents/rules/security-critical.mdc create mode 100644 templates/blank/.cursor/rules/access-control-advanced.md create mode 100644 templates/blank/.cursor/rules/access-control.md create mode 100644 templates/blank/.cursor/rules/adapters.md create mode 100644 templates/blank/.cursor/rules/collections.md create mode 100644 templates/blank/.cursor/rules/components.md create mode 100644 templates/blank/.cursor/rules/endpoints.md create mode 100644 templates/blank/.cursor/rules/field-type-guards.md create mode 100644 templates/blank/.cursor/rules/fields.md create mode 100644 templates/blank/.cursor/rules/hooks.md create mode 100644 templates/blank/.cursor/rules/payload-overview.md create mode 100644 templates/blank/.cursor/rules/plugin-development.md create mode 100644 templates/blank/.cursor/rules/queries.md create mode 100644 templates/blank/.cursor/rules/security-critical.mdc create mode 100644 templates/blank/AGENTS.md create mode 100644 templates/ecommerce/.cursor/rules/access-control-advanced.md create mode 100644 templates/ecommerce/.cursor/rules/access-control.md create mode 100644 templates/ecommerce/.cursor/rules/adapters.md create mode 100644 templates/ecommerce/.cursor/rules/collections.md create mode 100644 templates/ecommerce/.cursor/rules/components.md create mode 100644 templates/ecommerce/.cursor/rules/endpoints.md create mode 100644 templates/ecommerce/.cursor/rules/field-type-guards.md create mode 100644 templates/ecommerce/.cursor/rules/fields.md create mode 100644 templates/ecommerce/.cursor/rules/hooks.md create mode 100644 templates/ecommerce/.cursor/rules/payload-overview.md create mode 100644 templates/ecommerce/.cursor/rules/plugin-development.md create mode 100644 templates/ecommerce/.cursor/rules/queries.md create mode 100644 templates/ecommerce/.cursor/rules/security-critical.mdc create mode 100644 templates/ecommerce/AGENTS.md create mode 100644 templates/website/.cursor/rules/access-control-advanced.md create mode 100644 templates/website/.cursor/rules/access-control.md create mode 100644 templates/website/.cursor/rules/adapters.md create mode 100644 templates/website/.cursor/rules/collections.md create mode 100644 templates/website/.cursor/rules/components.md create mode 100644 templates/website/.cursor/rules/endpoints.md create mode 100644 templates/website/.cursor/rules/field-type-guards.md create mode 100644 templates/website/.cursor/rules/fields.md create mode 100644 templates/website/.cursor/rules/hooks.md create mode 100644 templates/website/.cursor/rules/payload-overview.md create mode 100644 templates/website/.cursor/rules/plugin-development.md create mode 100644 templates/website/.cursor/rules/queries.md create mode 100644 templates/website/.cursor/rules/security-critical.mdc create mode 100644 templates/website/AGENTS.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/access-control-advanced.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/access-control.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/adapters.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/collections.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/components.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/endpoints.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/field-type-guards.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/fields.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/hooks.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/payload-overview.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/plugin-development.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/queries.md create mode 100644 templates/with-cloudflare-d1/.cursor/rules/security-critical.mdc create mode 100644 templates/with-cloudflare-d1/AGENTS.md create mode 100644 templates/with-postgres/.cursor/rules/access-control-advanced.md create mode 100644 templates/with-postgres/.cursor/rules/access-control.md create mode 100644 templates/with-postgres/.cursor/rules/adapters.md create mode 100644 templates/with-postgres/.cursor/rules/collections.md create mode 100644 templates/with-postgres/.cursor/rules/components.md create mode 100644 templates/with-postgres/.cursor/rules/endpoints.md create mode 100644 templates/with-postgres/.cursor/rules/field-type-guards.md create mode 100644 templates/with-postgres/.cursor/rules/fields.md create mode 100644 templates/with-postgres/.cursor/rules/hooks.md create mode 100644 templates/with-postgres/.cursor/rules/payload-overview.md create mode 100644 templates/with-postgres/.cursor/rules/plugin-development.md create mode 100644 templates/with-postgres/.cursor/rules/queries.md create mode 100644 templates/with-postgres/.cursor/rules/security-critical.mdc create mode 100644 templates/with-postgres/AGENTS.md rename templates/with-postgres/src/migrations/{20251107_183854_initial.json => 20251216_194340_initial.json} (99%) rename templates/with-postgres/src/migrations/{20251107_183854_initial.ts => 20251216_194340_initial.ts} (100%) create mode 100644 templates/with-vercel-mongodb/.cursor/rules/access-control-advanced.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/access-control.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/adapters.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/collections.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/components.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/endpoints.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/field-type-guards.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/fields.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/hooks.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/payload-overview.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/plugin-development.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/queries.md create mode 100644 templates/with-vercel-mongodb/.cursor/rules/security-critical.mdc create mode 100644 templates/with-vercel-mongodb/AGENTS.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/access-control-advanced.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/access-control.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/adapters.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/collections.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/components.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/endpoints.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/field-type-guards.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/fields.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/hooks.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/payload-overview.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/plugin-development.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/queries.md create mode 100644 templates/with-vercel-postgres/.cursor/rules/security-critical.mdc create mode 100644 templates/with-vercel-postgres/AGENTS.md rename templates/with-vercel-postgres/src/migrations/{20251107_183841_initial.json => 20251216_194325_initial.json} (99%) rename templates/with-vercel-postgres/src/migrations/{20251107_183841_initial.ts => 20251216_194325_initial.ts} (100%) create mode 100644 templates/with-vercel-website/.cursor/rules/access-control-advanced.md create mode 100644 templates/with-vercel-website/.cursor/rules/access-control.md create mode 100644 templates/with-vercel-website/.cursor/rules/adapters.md create mode 100644 templates/with-vercel-website/.cursor/rules/collections.md create mode 100644 templates/with-vercel-website/.cursor/rules/components.md create mode 100644 templates/with-vercel-website/.cursor/rules/endpoints.md create mode 100644 templates/with-vercel-website/.cursor/rules/field-type-guards.md create mode 100644 templates/with-vercel-website/.cursor/rules/fields.md create mode 100644 templates/with-vercel-website/.cursor/rules/hooks.md create mode 100644 templates/with-vercel-website/.cursor/rules/payload-overview.md create mode 100644 templates/with-vercel-website/.cursor/rules/plugin-development.md create mode 100644 templates/with-vercel-website/.cursor/rules/queries.md create mode 100644 templates/with-vercel-website/.cursor/rules/security-critical.mdc create mode 100644 templates/with-vercel-website/AGENTS.md rename templates/with-vercel-website/src/migrations/{20251107_183848_initial.json => 20251216_194333_initial.json} (99%) rename templates/with-vercel-website/src/migrations/{20251107_183848_initial.ts => 20251216_194333_initial.ts} (100%) diff --git a/docs/plugins/overview.mdx b/docs/plugins/overview.mdx index f7e0eec8dad..ef2921c4705 100644 --- a/docs/plugins/overview.mdx +++ b/docs/plugins/overview.mdx @@ -49,6 +49,8 @@ Writing Plugins is no more complex than writing regular JavaScript. If you know Payload maintains a set of Official Plugins that solve for some of the common use cases. These plugins are maintained by the Payload team and its contributors and are guaranteed to be stable and up-to-date. - [Form Builder](./form-builder) +- [MCP](./mcp) +- [Multi-Tenant](./multi-tenant) - [Nested Docs](./nested-docs) - [Redirects](./redirects) - [Search](./search) diff --git a/templates/_agents/AGENTS.md b/templates/_agents/AGENTS.md new file mode 100644 index 00000000000..633b29b1f61 --- /dev/null +++ b/templates/_agents/AGENTS.md @@ -0,0 +1,1141 @@ +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default +6. **Access Control**: Ensure roles exist when modifiyng collection or globals with access controls + +### Code Validation + +- To validate typescript correctness after modifying code run `tsc --noEmit` +- Generate import maps after creating or modifying components. + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Configuration + +### Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Collections + +### Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +### Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Fields + +### Common Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## CRITICAL SECURITY PATTERNS + +### 1. Local API Access Control (MOST IMPORTANT) + +```typescript +// ❌ SECURITY BUG: Access control bypassed +await payload.find({ + collection: 'posts', + user: someUser, // Ignored! Operation runs with ADMIN privileges +}) + +// ✅ SECURE: Enforces user permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +### 2. Transaction Safety in Hooks + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ], +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ], +} +``` + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +### 3. Prevent Infinite Hook Loops + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ], +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ], +} +``` + +## Access Control + +### Collection-Level Access + +```typescript +import type { Access } from 'payload' + +// Boolean return +const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Query constraint (row-level security) +const ownPostsOnly: Access = ({ req: { user } }) => { + if (!user) return false + if (user?.roles?.includes('admin')) return true + + return { + author: { equals: user.id }, + } +} + +// Async access check +const projectMemberAccess: Access = async ({ req, id }) => { + const { user, payload } = req + + if (!user) return false + if (user.roles?.includes('admin')) return true + + const project = await payload.findByID({ + collection: 'projects', + id: id as string, + depth: 0, + }) + + return project.members?.includes(user.id) +} +``` + +### Field-Level Access + +```typescript +// Field access ONLY returns boolean (no query constraints) +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +### Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Hooks + +### Common Hook Patterns + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Queries + +### Local API + +```typescript +// Find with complex query +const posts = await payload.find({ + collection: 'posts', + where: { + and: [{ status: { equals: 'published' } }, { 'author.name': { contains: 'john' } }], + }, + depth: 2, // Populate relationships + limit: 10, + sort: '-createdAt', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const newPost = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { status: 'published' }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) +``` + +### Query Operators + +```typescript +// Equals +{ status: { equals: 'published' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater than / less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In array +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (geospatial) +{ location: { near: [-122.4194, 37.7749, 10000] } } +``` + +### AND/OR Logic + +```typescript +{ + or: [ + { status: { equals: 'published' } }, + { author: { equals: user.id } }, + ], +} + +{ + and: [ + { status: { equals: 'published' } }, + { featured: { equals: true } }, + ], +} +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Components + +The Admin Panel can be extensively customized using React Components. Custom Components can be Server Components (default) or Client Components. + +### Defining Components + +Components are defined using **file paths** (not direct imports) in your config: + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + // Logo and branding + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + + // Navigation + Nav: '/components/CustomNav', + beforeNavLinks: ['/components/CustomNavItem'], + afterNavLinks: ['/components/NavFooter'], + + // Header + header: ['/components/AnnouncementBanner'], + actions: ['/components/ClearCache', '/components/Preview'], + + // Dashboard + beforeDashboard: ['/components/WelcomeMessage'], + afterDashboard: ['/components/Analytics'], + + // Auth + beforeLogin: ['/components/SSOButtons'], + logout: { Button: '/components/LogoutButton' }, + + // Settings + settingsMenu: ['/components/SettingsMenu'], + + // Views + views: { + dashboard: { Component: '/components/CustomDashboard' }, + }, + }, + }, +}) +``` + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Server vs Client Components + +**All components are Server Components by default** (can use Local API directly): + +```tsx +// Server Component (default) +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const posts = await payload.find({ collection: 'posts' }) + return
{posts.totalDocs} posts
+} + +export default MyServerComponent +``` + +**Client Components** need the `'use client'` directive: + +```tsx +'use client' +import { useState } from 'react' +import { useAuth } from '@payloadcms/ui' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + const { user } = useAuth() + + return ( + + ) +} +``` + +### Using Hooks (Client Components Only) + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Document info (id, collection, etc.) + useField, // Field value and setter + useForm, // Form state + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +### Collection/Global Components + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/SaveDraft', + PublishButton: '/components/Publish', + }, + + // List view + list: { + Header: '/components/ListHeader', + beforeList: ['/components/BulkActions'], + afterList: ['/components/ListFooter'], + }, + }, + }, +} +``` + +### Field Components + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + // Edit view field + Field: '/components/StatusField', + // List view cell + Cell: '/components/StatusCell', + // Field label + Label: '/components/StatusLabel', + // Field description + Description: '/components/StatusDescription', + // Error message + Error: '/components/StatusError', + }, + }, +} +``` + +**UI Field** (presentational only, no data): + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +### Performance Best Practices + +1. **Import correctly:** + + - Admin Panel: `import { Button } from '@payloadcms/ui'` + - Frontend: `import { Button } from '@payloadcms/ui/elements/Button'` + +2. **Optimize re-renders:** + + ```tsx + // ❌ BAD: Re-renders on every form change + const { fields } = useForm() + + // ✅ GOOD: Only re-renders when specific field changes + const value = useFormFields(([fields]) => fields[path]) + ``` + +3. **Prefer Server Components** - Only use Client Components when you need: + + - State (useState, useReducer) + - Effects (useEffect) + - Event handlers (onClick, onChange) + - Browser APIs (localStorage, window) + +4. **Minimize serialized props** - Server Components serialize props sent to client + +### Styling Components + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Content
+} +``` + +```scss +// Use Payload's CSS variables +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} + +// Import Payload's SCSS library +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +### Type Safety + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, + SelectFieldServerComponent, + // ... etc +} from 'payload' + +export const MyField: TextFieldClientComponent = (props) => { + // Fully typed props +} +``` + +### Import Map + +Payload auto-generates `app/(payload)/admin/importMap.js` to resolve component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Set custom location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Custom Endpoints + +```typescript +import type { Endpoint } from 'payload' +import { APIError } from 'payload' + +// Always check authentication +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} + +// Route parameters +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Drafts & Versions + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} + +// Create draft +await payload.create({ + collection: 'pages', + data: { title: 'Draft Page' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft if available +}) +``` + +## Field Type Guards + +```typescript +import { + fieldAffectsData, + fieldHasSubFields, + fieldIsArrayType, + fieldIsBlockType, + fieldSupportsMany, + fieldHasMaxDepth, +} from 'payload' + +function processField(field: Field) { + // Check if field stores data + if (fieldAffectsData(field)) { + console.log(field.name) // Safe to access + } + + // Check if field has nested fields + if (fieldHasSubFields(field)) { + field.fields.forEach(processField) // Safe to access + } + + // Check field type + if (fieldIsArrayType(field)) { + console.log(field.minRows, field.maxRows) + } + + // Check capabilities + if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') + } +} +``` + +## Plugins + +### Using Plugins + +```typescript +import { seoPlugin } from '@payloadcms/plugin-seo' +import { redirectsPlugin } from '@payloadcms/plugin-redirects' + +export default buildConfig({ + plugins: [ + seoPlugin({ + collections: ['posts', 'pages'], + }), + redirectsPlugin({ + collections: ['pages'], + }), + ], +}) +``` + +### Creating Plugins + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + collections?: string[] + enabled?: boolean +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...collection.fields, { name: 'pluginField', type: 'text' }], + } + } + return collection + }), + }) +``` + +## Best Practices + +### Security + +1. Always set `overrideAccess: false` when passing `user` to Local API +2. Field-level access only returns boolean (no query constraints) +3. Default to restrictive access, gradually add permissions +4. Never trust client-provided data +5. Use `saveToJWT: true` for roles to avoid database lookups + +### Performance + +1. Index frequently queried fields +2. Use `select` to limit returned fields +3. Set `maxDepth` on relationships to prevent over-fetching +4. Use query constraints over async operations in access control +5. Cache expensive operations in `req.context` + +### Data Integrity + +1. Always pass `req` to nested operations in hooks +2. Use context flags to prevent infinite hook loops +3. Enable transactions for MongoDB (requires replica set) and Postgres +4. Use `beforeValidate` for data formatting +5. Use `beforeChange` for business logic + +### Type Safety + +1. Run `generate:types` after schema changes +2. Import types from generated `payload-types.ts` +3. Type your user object: `import type { User } from '@/payload-types'` +4. Use `as const` for field options +5. Use field type guards for runtime type checking + +### Organization + +1. Keep collections in separate files +2. Extract access control to `access/` directory +3. Extract hooks to `hooks/` directory +4. Use reusable field factories for common patterns +5. Document complex access control with comments + +## Common Gotchas + +1. **Local API Default**: Access control bypassed unless `overrideAccess: false` +2. **Transaction Safety**: Missing `req` in nested operations breaks atomicity +3. **Hook Loops**: Operations in hooks can trigger the same hooks +4. **Field Access**: Cannot use query constraints, only boolean +5. **Relationship Depth**: Default depth is 2, set to 0 for IDs only +6. **Draft Status**: `_status` field auto-injected when drafts enabled +7. **Type Generation**: Types not updated until `generate:types` runs +8. **MongoDB Transactions**: Require replica set configuration +9. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +10. **Point Fields**: Not supported in SQLite + +## Additional Context Files + +For deeper exploration of specific topics, refer to the context files located in `.cursor/rules/`: + +### Available Context Files + +1. **`payload-overview.md`** - High-level architecture and core concepts + + - Payload structure and initialization + - Configuration fundamentals + - Database adapters overview + +2. **`security-critical.md`** - Critical security patterns (⚠️ IMPORTANT) + + - Local API access control + - Transaction safety in hooks + - Preventing infinite hook loops + +3. **`collections.md`** - Collection configurations + + - Basic collection patterns + - Auth collections with RBAC + - Upload collections + - Drafts and versioning + - Globals + +4. **`fields.md`** - Field types and patterns + + - All field types with examples + - Conditional fields + - Virtual fields + - Field validation + - Common field patterns + +5. **`field-type-guards.md`** - TypeScript field type utilities + + - Field type checking utilities + - Safe type narrowing + - Runtime field validation + +6. **`access-control.md`** - Permission patterns + + - Collection-level access + - Field-level access + - Row-level security + - RBAC patterns + - Multi-tenant access control + +7. **`access-control-advanced.md`** - Complex access patterns + + - Nested document access + - Cross-collection permissions + - Dynamic role hierarchies + - Performance optimization + +8. **`hooks.md`** - Lifecycle hooks + + - Collection hooks + - Field hooks + - Hook context patterns + - Common hook recipes + +9. **`queries.md`** - Database operations + + - Local API usage + - Query operators + - Complex queries with AND/OR + - Performance optimization + +10. **`endpoints.md`** - Custom API endpoints + + - REST endpoint patterns + - Authentication in endpoints + - Error handling + - Route parameters + +11. **`adapters.md`** - Database and storage adapters + + - MongoDB, PostgreSQL, SQLite patterns + - Storage adapter usage (S3, Azure, GCS, etc.) + - Custom adapter development + +12. **`plugin-development.md`** - Creating plugins + + - Plugin architecture + - Modifying configuration + - Plugin hooks + - Best practices + +13. **`components.md`** - Custom Components + + - Component types (Root, Collection, Global, Field) + - Server vs Client Components + - Component paths and definition + - Default and custom props + - Using hooks + - Performance best practices + - Styling components + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/_agents/rules/access-control-advanced.md b/templates/_agents/rules/access-control-advanced.md new file mode 100644 index 00000000000..68f52fd1287 --- /dev/null +++ b/templates/_agents/rules/access-control-advanced.md @@ -0,0 +1,519 @@ +--- +title: Access Control - Advanced Patterns +description: Context-aware, time-based, subscription-based access, factory functions, templates +tags: [payload, access-control, security, advanced, performance] +priority: high +--- + +# Advanced Access Control Patterns + +Advanced access control patterns including context-aware access, time-based restrictions, factory functions, and production templates. + +## Context-Aware Access Patterns + +### Locale-Specific Access + +```typescript +import type { Access } from 'payload' + +export const localeSpecificAccess: Access = ({ req: { user, locale } }) => { + // Authenticated users can access all locales + if (user) return true + + // Public users can only access English content + if (locale === 'en') return true + + return false +} +``` + +### Device-Specific Access + +```typescript +export const mobileOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return /mobile|android|iphone/i.test(userAgent) +} + +export const desktopOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return !/mobile|android|iphone/i.test(userAgent) +} +``` + +### IP-Based Access + +```typescript +export const restrictedIpAccess = (allowedIps: string[]): Access => { + return ({ req: { headers } }) => { + const ip = headers?.get('x-forwarded-for') || headers?.get('x-real-ip') + return allowedIps.includes(ip || '') + } +} + +// Usage +const internalIps = ['192.168.1.0/24', '10.0.0.5'] + +export const InternalDocs: CollectionConfig = { + slug: 'internal-docs', + access: { + read: restrictedIpAccess(internalIps), + }, +} +``` + +## Time-Based Access Patterns + +### Today's Records Only + +```typescript +export const todayOnlyAccess: Access = ({ req: { user } }) => { + if (!user) return false + + const now = new Date() + const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000) + + return { + createdAt: { + greater_than_equal: startOfDay.toISOString(), + less_than: endOfDay.toISOString(), + }, + } +} +``` + +### Recent Records (Last N Days) + +```typescript +export const recentRecordsAccess = (days: number): Access => { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - days) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} + +// Usage: Users see only last 30 days, admins see all +export const Logs: CollectionConfig = { + slug: 'logs', + access: { + read: recentRecordsAccess(30), + }, +} +``` + +### Scheduled Content (Publish Date Range) + +```typescript +export const scheduledContentAccess: Access = ({ req: { user } }) => { + // Editors see all content + if (user?.roles?.includes('admin') || user?.roles?.includes('editor')) { + return true + } + + const now = new Date().toISOString() + + // Public sees only content within publish window + return { + and: [ + { publishDate: { less_than_equal: now } }, + { + or: [{ unpublishDate: { exists: false } }, { unpublishDate: { greater_than: now } }], + }, + ], + } +} +``` + +## Subscription-Based Access + +### Active Subscription Required + +```typescript +export const activeSubscriptionAccess: Access = async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + return subscription?.status === 'active' + } catch { + return false + } +} +``` + +### Subscription Tier-Based Access + +```typescript +export const tierBasedAccess = (requiredTier: string): Access => { + const tierHierarchy = ['free', 'basic', 'pro', 'enterprise'] + + return async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + if (subscription?.status !== 'active') return false + + const userTierIndex = tierHierarchy.indexOf(subscription.tier) + const requiredTierIndex = tierHierarchy.indexOf(requiredTier) + + return userTierIndex >= requiredTierIndex + } catch { + return false + } + } +} + +// Usage +export const EnterpriseFeatures: CollectionConfig = { + slug: 'enterprise-features', + access: { + read: tierBasedAccess('enterprise'), + }, +} +``` + +## Factory Functions + +### createRoleBasedAccess + +```typescript +export function createRoleBasedAccess(roles: string[]): Access { + return ({ req: { user } }) => { + if (!user) return false + return roles.some((role) => user.roles?.includes(role)) + } +} + +// Usage +const adminOrEditor = createRoleBasedAccess(['admin', 'editor']) +const moderatorAccess = createRoleBasedAccess(['admin', 'moderator']) +``` + +### createOrgScopedAccess + +```typescript +export function createOrgScopedAccess(allowAdmin = true): Access { + return ({ req: { user } }) => { + if (!user) return false + if (allowAdmin && user.roles?.includes('admin')) return true + + return { + organizationId: { in: user.organizationIds || [] }, + } + } +} + +// Usage +const orgScoped = createOrgScopedAccess() // Admins bypass +const strictOrgScoped = createOrgScopedAccess(false) // Admins also scoped +``` + +### createTeamBasedAccess + +```typescript +export function createTeamBasedAccess(teamField = 'teamId'): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + [teamField]: { in: user.teamIds || [] }, + } + } +} +``` + +### createTimeLimitedAccess + +```typescript +export function createTimeLimitedAccess(daysAccess: number): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - daysAccess) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} +``` + +## Configuration Templates + +### Public + Authenticated Collection + +```typescript +export const PublicAuthCollection: CollectionConfig = { + slug: 'posts', + access: { + // Only admins/editors can create + create: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Authenticated users see all, public sees only published + read: ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } + }, + + // Only admins/editors can update + update: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Only admins can delete + delete: ({ req: { user } }) => { + return user?.roles?.includes('admin') || false + }, + }, + versions: { + drafts: true, + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'content', type: 'richText', required: true }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], +} +``` + +### Self-Service Collection + +```typescript +export const SelfServiceCollection: CollectionConfig = { + slug: 'users', + auth: true, + access: { + // Admins can create users + create: ({ req: { user } }) => user?.roles?.includes('admin') || false, + + // Anyone can read user profiles + read: () => true, + + // Users can update self, admins can update anyone + update: ({ req: { user }, id }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + return user.id === id + }, + + // Only admins can delete + delete: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + fields: [ + { name: 'name', type: 'text', required: true }, + { name: 'email', type: 'email', required: true }, + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + access: { + // Only admins can read/update roles + read: ({ req: { user } }) => user?.roles?.includes('admin') || false, + update: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + }, + ], +} +``` + +## Performance Considerations + +### Avoid Async Operations in Hot Paths + +```typescript +// ❌ Slow: Multiple sequential async calls +export const slowAccess: Access = async ({ req: { user } }) => { + const org = await req.payload.findByID({ collection: 'orgs', id: user.orgId }) + const team = await req.payload.findByID({ collection: 'teams', id: user.teamId }) + const subscription = await req.payload.findByID({ collection: 'subs', id: user.subId }) + + return org.active && team.active && subscription.active +} + +// ✅ Fast: Use query constraints or cache in context +export const fastAccess: Access = ({ req: { user, context } }) => { + // Cache expensive lookups + if (!context.orgStatus) { + context.orgStatus = checkOrgStatus(user.orgId) + } + + return context.orgStatus +} +``` + +### Query Constraint Optimization + +```typescript +// ❌ Avoid: Non-indexed fields in constraints +export const slowQuery: Access = () => ({ + 'metadata.internalCode': { equals: 'ABC123' }, // Slow if not indexed +}) + +// ✅ Better: Use indexed fields +export const fastQuery: Access = () => ({ + status: { equals: 'active' }, // Indexed field + organizationId: { in: ['org1', 'org2'] }, // Indexed field +}) +``` + +### Field Access on Large Arrays + +```typescript +// ❌ Slow: Complex access on array fields +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: async ({ req }) => { + // Async call runs for EVERY array item + const result = await expensiveCheck() + return result + }, + }, + }, + ], +} + +// ✅ Fast: Simple checks or cache result +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: ({ req: { user }, context }) => { + // Cache once, reuse for all items + if (context.canReadSecret === undefined) { + context.canReadSecret = user?.roles?.includes('admin') + } + return context.canReadSecret + }, + }, + }, + ], +} +``` + +### Avoid N+1 Queries + +```typescript +// ❌ N+1 Problem: Query per access check +export const n1Access: Access = async ({ req, id }) => { + // Runs for EACH document in list + const doc = await req.payload.findByID({ collection: 'docs', id }) + return doc.isPublic +} + +// ✅ Better: Use query constraint to filter at DB level +export const efficientAccess: Access = () => { + return { isPublic: { equals: true } } +} +``` + +## Debugging Tips + +### Log Access Check Execution + +```typescript +export const debugAccess: Access = ({ req: { user }, id }) => { + console.log('Access check:', { + userId: user?.id, + userRoles: user?.roles, + docId: id, + timestamp: new Date().toISOString(), + }) + return true +} +``` + +### Verify Arguments Availability + +```typescript +export const checkArgsAccess: Access = (args) => { + console.log('Available arguments:', { + hasReq: 'req' in args, + hasUser: args.req?.user ? 'yes' : 'no', + hasId: args.id ? 'provided' : 'undefined', + hasData: args.data ? 'provided' : 'undefined', + }) + return true +} +``` + +### Test Access Without User + +```typescript +// In test/development +const testAccess = await payload.find({ + collection: 'posts', + overrideAccess: false, // Enforce access control + user: undefined, // Simulate no user +}) + +console.log('Public access result:', testAccess.docs.length) +``` + +## Best Practices + +1. **Default Deny**: Start with restrictive access, gradually add permissions +2. **Type Guards**: Use TypeScript for user type safety +3. **Validate Data**: Never trust frontend-provided IDs or data +4. **Async for Critical Checks**: Use async operations for important security decisions +5. **Consistent Logic**: Apply same rules at field and collection levels +6. **Test Edge Cases**: Test with no user, wrong user, admin user scenarios +7. **Monitor Access**: Log failed access attempts for security review +8. **Regular Audit**: Review access rules quarterly or after major changes +9. **Cache Wisely**: Use `req.context` for expensive operations +10. **Document Intent**: Add comments explaining complex access rules +11. **Avoid Secrets in Client**: Never expose sensitive logic to client-side +12. **Handle Errors Gracefully**: Access functions should return `false` on error, not throw +13. **Test Local API**: Remember to set `overrideAccess: false` when testing +14. **Consider Performance**: Measure impact of async operations +15. **Principle of Least Privilege**: Grant minimum access required + +## Performance Summary + +**Minimize Async Operations**: Use query constraints over async lookups when possible + +**Cache Expensive Checks**: Store results in `req.context` for reuse + +**Index Query Fields**: Ensure fields in query constraints are indexed + +**Avoid Complex Logic in Array Fields**: Simple boolean checks preferred + +**Use Query Constraints**: Let database filter rather than loading all records diff --git a/templates/_agents/rules/access-control.md b/templates/_agents/rules/access-control.md new file mode 100644 index 00000000000..7b9a0a4ba5c --- /dev/null +++ b/templates/_agents/rules/access-control.md @@ -0,0 +1,225 @@ +--- +title: Access Control +description: Collection, field, and global access control patterns +tags: [payload, access-control, security, permissions, rbac] +--- + +# Payload CMS Access Control + +## Access Control Layers + +1. **Collection-Level**: Controls operations on entire documents (create, read, update, delete, admin) +2. **Field-Level**: Controls access to individual fields (create, read, update) +3. **Global-Level**: Controls access to global documents (read, update) + +## Collection Access Control + +```typescript +import type { Access } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + // Boolean: Only authenticated users can create + create: ({ req: { user } }) => Boolean(user), + + // Query constraint: Public sees published, users see all + read: ({ req: { user } }) => { + if (user) return true + return { status: { equals: 'published' } } + }, + + // User-specific: Admins or document owner + update: ({ req: { user }, id }) => { + if (user?.roles?.includes('admin')) return true + return { author: { equals: user?.id } } + }, + + // Async: Check related data + delete: async ({ req, id }) => { + const hasComments = await req.payload.count({ + collection: 'comments', + where: { post: { equals: id } }, + }) + return hasComments === 0 + }, + }, +} +``` + +## Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Row-Level Security + +```typescript +// Organization-scoped access +export const organizationScoped: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + + // Users see only their organization's data + return { + organization: { + equals: user?.organization, + }, + } +} + +// Team-based access +export const teamMemberAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + 'team.members': { + contains: user.id, + }, + } +} +``` + +## Field Access Control + +**Field access ONLY returns boolean** (no query constraints). + +```typescript +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +## RBAC Pattern + +Payload does NOT provide a roles system by default. Add a `roles` field to your auth collection: + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Multi-Tenant Access Control + +```typescript +interface User { + id: string + tenantId: string + roles?: string[] +} + +const tenantAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('super-admin')) return true + + return { + tenant: { + equals: (user as User).tenantId, + }, + } +} + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + create: tenantAccess, + read: tenantAccess, + update: tenantAccess, + delete: tenantAccess, + }, + fields: [ + { + name: 'tenant', + type: 'text', + required: true, + access: { + update: ({ req: { user } }) => user?.roles?.includes('super-admin'), + }, + hooks: { + beforeChange: [ + ({ req, operation, value }) => { + if (operation === 'create' && !value) { + return (req.user as User)?.tenantId + } + return value + }, + ], + }, + }, + ], +} +``` + +## Important Notes + +1. **Local API Default**: Access control is **skipped by default** in Local API (`overrideAccess: true`). When passing a `user` parameter, you must set `overrideAccess: false`: + +```typescript +// ❌ WRONG: Passes user but bypasses access control +await payload.find({ + collection: 'posts', + user: someUser, +}) + +// ✅ CORRECT: Respects the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // Required to enforce access control +}) +``` + +2. **Field Access Limitations**: Field-level access does NOT support query constraints - only boolean returns. + +3. **Admin Panel Visibility**: The `admin` access control determines if a collection appears in the admin panel for a user. diff --git a/templates/_agents/rules/adapters.md b/templates/_agents/rules/adapters.md new file mode 100644 index 00000000000..49b8b3367fc --- /dev/null +++ b/templates/_agents/rules/adapters.md @@ -0,0 +1,209 @@ +--- +title: Database Adapters & Transactions +description: Database adapters, storage, email, and transaction patterns +tags: [payload, database, mongodb, postgres, sqlite, transactions] +--- + +# Payload CMS Adapters + +## Database Adapters + +### MongoDB + +```typescript +import { mongooseAdapter } from '@payloadcms/db-mongodb' + +export default buildConfig({ + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +### Postgres + +```typescript +import { postgresAdapter } from '@payloadcms/db-postgres' + +export default buildConfig({ + db: postgresAdapter({ + pool: { + connectionString: process.env.DATABASE_URI, + }, + push: false, // Don't auto-push schema changes + migrationDir: './migrations', + }), +}) +``` + +### SQLite + +```typescript +import { sqliteAdapter } from '@payloadcms/db-sqlite' + +export default buildConfig({ + db: sqliteAdapter({ + client: { + url: 'file:./payload.db', + }, + transactionOptions: {}, // Enable transactions (disabled by default) + }), +}) +``` + +## Transactions + +Payload automatically uses transactions for all-or-nothing database operations. + +### Threading req Through Operations + +**CRITICAL**: When performing nested operations in hooks, always pass `req` to maintain transaction context. + +```typescript +// ✅ CORRECT: Thread req through nested operations +const resaveChildren: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + // Find children - pass req + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + req, // Maintains transaction context + }) + + // Update each child - pass req + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + req, // Same transaction as parent operation + }) + } +} + +// ❌ WRONG: Missing req breaks transaction +const brokenHook: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + // Missing req - separate transaction or no transaction + }) + + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + // Missing req - if parent operation fails, these updates persist + }) + } +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +### Manual Transaction Control + +```typescript +const transactionID = await payload.db.beginTransaction() +try { + await payload.create({ + collection: 'orders', + data: orderData, + req: { transactionID }, + }) + await payload.update({ + collection: 'inventory', + id: itemId, + data: { stock: newStock }, + req: { transactionID }, + }) + await payload.db.commitTransaction(transactionID) +} catch (error) { + await payload.db.rollbackTransaction(transactionID) + throw error +} +``` + +## Storage Adapters + +Available storage adapters: + +- **@payloadcms/storage-s3** - AWS S3 +- **@payloadcms/storage-azure** - Azure Blob Storage +- **@payloadcms/storage-gcs** - Google Cloud Storage +- **@payloadcms/storage-r2** - Cloudflare R2 +- **@payloadcms/storage-vercel-blob** - Vercel Blob +- **@payloadcms/storage-uploadthing** - Uploadthing + +### AWS S3 + +```typescript +import { s3Storage } from '@payloadcms/storage-s3' + +export default buildConfig({ + plugins: [ + s3Storage({ + collections: { + media: true, + }, + bucket: process.env.S3_BUCKET, + config: { + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + region: process.env.S3_REGION, + }, + }), + ], +}) +``` + +## Email Adapters + +### Nodemailer (SMTP) + +```typescript +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' + +export default buildConfig({ + email: nodemailerAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + transportOptions: { + host: process.env.SMTP_HOST, + port: 587, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }, + }), +}) +``` + +### Resend + +```typescript +import { resendAdapter } from '@payloadcms/email-resend' + +export default buildConfig({ + email: resendAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + apiKey: process.env.RESEND_API_KEY, + }), +}) +``` + +## Important Notes + +1. **MongoDB Transactions**: Require replica set configuration +2. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +3. **Pass req**: Always pass `req` to nested operations in hooks for transaction safety +4. **Point Fields**: Not supported in SQLite diff --git a/templates/_agents/rules/collections.md b/templates/_agents/rules/collections.md new file mode 100644 index 00000000000..af625108e60 --- /dev/null +++ b/templates/_agents/rules/collections.md @@ -0,0 +1,171 @@ +--- +title: Collections +description: Collection configurations and patterns +tags: [payload, collections, auth, upload, drafts] +--- + +# Payload CMS Collections + +## Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +## Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Upload Collection + +```typescript +export const Media: CollectionConfig = { + slug: 'media', + upload: { + staticDir: 'media', + mimeTypes: ['image/*'], + imageSizes: [ + { + name: 'thumbnail', + width: 400, + height: 300, + position: 'centre', + }, + { + name: 'card', + width: 768, + height: 1024, + }, + ], + adminThumbnail: 'thumbnail', + focalPoint: true, + crop: true, + }, + access: { + read: () => true, + }, + fields: [ + { + name: 'alt', + type: 'text', + required: true, + }, + ], +} +``` + +## Versioning & Drafts + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} +``` + +### Draft API Usage + +```typescript +// Create draft +await payload.create({ + collection: 'posts', + data: { title: 'Draft Post' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft version if exists +}) +``` + +## Globals + +Globals are single-instance documents (not collections). + +```typescript +import type { GlobalConfig } from 'payload' + +export const Header: GlobalConfig = { + slug: 'header', + label: 'Header', + admin: { + group: 'Settings', + }, + fields: [ + { + name: 'logo', + type: 'upload', + relationTo: 'media', + required: true, + }, + { + name: 'nav', + type: 'array', + maxRows: 8, + fields: [ + { + name: 'link', + type: 'relationship', + relationTo: 'pages', + }, + { + name: 'label', + type: 'text', + }, + ], + }, + ], +} +``` diff --git a/templates/_agents/rules/components.md b/templates/_agents/rules/components.md new file mode 100644 index 00000000000..8610b8d7b33 --- /dev/null +++ b/templates/_agents/rules/components.md @@ -0,0 +1,794 @@ +# Custom Components in Payload CMS + +Custom Components allow you to fully customize the Admin Panel by swapping in your own React components. You can replace nearly every part of the interface or add entirely new functionality. + +## Component Types + +There are four main types of Custom Components: + +1. **Root Components** - Affect the Admin Panel globally (logo, nav, header) +2. **Collection Components** - Specific to collection views +3. **Global Components** - Specific to global document views +4. **Field Components** - Custom field UI and cells + +## Defining Custom Components + +### Component Paths + +Components are defined using file paths (not direct imports) to keep the config lightweight and Node.js compatible. + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + logout: { + Button: '/src/components/Logout#MyComponent', // Named export + }, + Nav: '/src/components/Nav', // Default export + }, + }, +}) +``` + +**Component Path Rules:** + +1. Paths are relative to project root (or `config.admin.importMap.baseDir`) +2. For **named exports**: append `#ExportName` or use `exportName` property +3. For **default exports**: no suffix needed +4. File extensions can be omitted + +### Component Config Object + +Instead of a string path, you can pass a config object: + +```typescript +{ + logout: { + Button: { + path: '/src/components/Logout', + exportName: 'MyComponent', + clientProps: { customProp: 'value' }, + serverProps: { asyncData: someData }, + }, + }, +} +``` + +**Config Properties:** + +| Property | Description | +| ------------- | ----------------------------------------------------- | +| `path` | File path to component (named exports via `#`) | +| `exportName` | Named export (alternative to `#` in path) | +| `clientProps` | Props for Client Components (must be serializable) | +| `serverProps` | Props for Server Components (can be non-serializable) | + +### Setting Base Directory + +```typescript +import path from 'path' +import { fileURLToPath } from 'node:url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), // Set base directory + }, + components: { + Nav: '/components/Nav', // Now relative to src/ + }, + }, +}) +``` + +## Server vs Client Components + +**All components are React Server Components by default.** + +### Server Components (Default) + +Can use Local API directly, perform async operations, and access full Payload instance. + +```tsx +import React from 'react' +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const page = await payload.findByID({ + collection: 'pages', + id: '123', + }) + + return

{page.title}

+} + +export default MyServerComponent +``` + +### Client Components + +Use the `'use client'` directive for interactivity, hooks, state, etc. + +```tsx +'use client' +import React, { useState } from 'react' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + + return +} +``` + +**Important:** Client Components cannot receive non-serializable props (functions, class instances, etc.). Payload automatically strips these when passing to client components. + +## Default Props + +All Custom Components receive these props by default: + +| Prop | Description | Type | +| --------- | ---------------------------------------- | --------- | +| `payload` | Payload instance (Local API access) | `Payload` | +| `i18n` | Internationalization object | `I18n` | +| `locale` | Current locale (if localization enabled) | `string` | + +**Server Component Example:** + +```tsx +async function MyComponent({ payload, i18n, locale }) { + const data = await payload.find({ + collection: 'posts', + locale, + }) + + return
{data.docs.length} posts
+} +``` + +**Client Component Example:** + +```tsx +'use client' +import { usePayload, useLocale, useTranslation } from '@payloadcms/ui' + +export function MyComponent() { + // Access via hooks in client components + const { getLocal, getByID } = usePayload() + const locale = useLocale() + const { t, i18n } = useTranslation() + + return
{t('myKey')}
+} +``` + +## Custom Props + +Pass additional props using `clientProps` or `serverProps`: + +```typescript +{ + logout: { + Button: { + path: '/components/Logout', + clientProps: { + buttonText: 'Sign Out', + onLogout: () => console.log('Logged out'), + }, + }, + }, +} +``` + +Receive in component: + +```tsx +'use client' +export function Logout({ buttonText, onLogout }) { + return +} +``` + +## Root Components + +Root Components affect the entire Admin Panel. + +### Available Root Components + +| Component | Description | Config Path | +| ----------------- | -------------------------------- | ---------------------------------- | +| `Nav` | Entire navigation sidebar | `admin.components.Nav` | +| `graphics.Icon` | Small icon (used in nav) | `admin.components.graphics.Icon` | +| `graphics.Logo` | Full logo (used on login) | `admin.components.graphics.Logo` | +| `logout.Button` | Logout button | `admin.components.logout.Button` | +| `actions` | Header actions (array) | `admin.components.actions` | +| `header` | Above header (array) | `admin.components.header` | +| `beforeDashboard` | Before dashboard content (array) | `admin.components.beforeDashboard` | +| `afterDashboard` | After dashboard content (array) | `admin.components.afterDashboard` | +| `beforeLogin` | Before login form (array) | `admin.components.beforeLogin` | +| `afterLogin` | After login form (array) | `admin.components.afterLogin` | +| `beforeNavLinks` | Before nav links (array) | `admin.components.beforeNavLinks` | +| `afterNavLinks` | After nav links (array) | `admin.components.afterNavLinks` | +| `settingsMenu` | Settings menu items (array) | `admin.components.settingsMenu` | +| `providers` | Custom React Context providers | `admin.components.providers` | +| `views` | Custom views (dashboard, etc.) | `admin.components.views` | + +### Example: Custom Logo + +```typescript +export default buildConfig({ + admin: { + components: { + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + }, + }, +}) +``` + +```tsx +// components/Logo.tsx +export default function Logo() { + return My Brand +} +``` + +### Example: Header Actions + +```typescript +export default buildConfig({ + admin: { + components: { + actions: ['/components/ClearCacheButton', '/components/PreviewButton'], + }, + }, +}) +``` + +```tsx +// components/ClearCacheButton.tsx +'use client' +export default function ClearCacheButton() { + return ( + + ) +} +``` + +## Collection Components + +Collection Components are specific to a collection's views. + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view components + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/CustomSaveDraft', + PublishButton: '/components/CustomPublish', + }, + + // List view components + list: { + Header: '/components/PostsListHeader', + beforeList: ['/components/ListFilters'], + afterList: ['/components/ListFooter'], + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Global Components + +Similar to Collection Components but for Global documents. + +```typescript +import type { GlobalConfig } from 'payload' + +export const Settings: GlobalConfig = { + slug: 'settings', + admin: { + components: { + edit: { + PreviewButton: '/components/SettingsPreview', + SaveButton: '/components/SettingsSave', + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Field Components + +Customize how fields render in Edit and List views. + +### Field Component (Edit View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Field: '/components/StatusField', + }, + }, +} +``` + +```tsx +// components/StatusField.tsx +'use client' +import { useField } from '@payloadcms/ui' +import type { SelectFieldClientComponent } from 'payload' + +export const StatusField: SelectFieldClientComponent = ({ path, field }) => { + const { value, setValue } = useField({ path }) + + return ( +
+ + +
+ ) +} +``` + +### Cell Component (List View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Cell: '/components/StatusCell', + }, + }, +} +``` + +```tsx +// components/StatusCell.tsx +import type { SelectFieldCellComponent } from 'payload' + +export const StatusCell: SelectFieldCellComponent = ({ data, cellData }) => { + const isPublished = cellData === 'published' + + return ( + + {cellData} + + ) +} +``` + +### UI Field (Presentational Only) + +Special field type for adding custom UI without affecting data: + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +```tsx +// components/RefundButton.tsx +'use client' +import { useDocumentInfo } from '@payloadcms/ui' + +export default function RefundButton() { + const { id } = useDocumentInfo() + + return ( + + ) +} +``` + +## Using Hooks + +Payload provides many React hooks for Client Components: + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Current document info (id, slug, etc.) + useField, // Field value and setValue + useForm, // Form state and dispatch + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +**Important:** These hooks only work in Client Components within the Admin Panel context. + +## Accessing Payload Config + +**In Server Components:** + +```tsx +async function MyServerComponent({ payload }) { + const { config } = payload + return
{config.serverURL}
+} +``` + +**In Client Components:** + +```tsx +'use client' +import { useConfig } from '@payloadcms/ui' + +export function MyClientComponent() { + const { config } = useConfig() // Client-safe config + return
{config.serverURL}
+} +``` + +**Important:** Client Components receive a serializable version of the config (functions, validation, etc. are stripped). + +## Field Config Access + +**Server Component:** + +```tsx +import type { TextFieldServerComponent } from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = ({ field }) => { + return
Field name: {field.name}
+} +``` + +**Client Component:** + +```tsx +'use client' +import type { TextFieldClientComponent } from 'payload' + +export const MyFieldComponent: TextFieldClientComponent = ({ clientField }) => { + // clientField has non-serializable props removed + return
Field name: {clientField.name}
+} +``` + +## Translations (i18n) + +**Server Component:** + +```tsx +import { getTranslation } from '@payloadcms/translations' + +async function MyServerComponent({ i18n }) { + const translatedTitle = getTranslation(myTranslation, i18n) + return

{translatedTitle}

+} +``` + +**Client Component:** + +```tsx +'use client' +import { useTranslation } from '@payloadcms/ui' + +export function MyClientComponent() { + const { t, i18n } = useTranslation() + + return ( +
+

{t('namespace:key', { variable: 'value' })}

+

Language: {i18n.language}

+
+ ) +} +``` + +## Styling Components + +### Using CSS Variables + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Custom Component
+} +``` + +```scss +// styles.scss +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} +``` + +### Importing Payload SCSS + +```scss +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +## Common Patterns + +### Conditional Field Visibility + +```tsx +'use client' +import { useFormFields } from '@payloadcms/ui' +import type { TextFieldClientComponent } from 'payload' + +export const ConditionalField: TextFieldClientComponent = ({ path }) => { + const showField = useFormFields(([fields]) => fields.enableFeature?.value) + + if (!showField) return null + + return +} +``` + +### Loading Data from API + +```tsx +'use client' +import { useState, useEffect } from 'react' + +export function DataLoader() { + const [data, setData] = useState(null) + + useEffect(() => { + fetch('/api/custom-data') + .then((res) => res.json()) + .then(setData) + }, []) + + return
{JSON.stringify(data)}
+} +``` + +### Using Local API in Server Components + +```tsx +import type { Payload } from 'payload' + +async function RelatedPosts({ payload, id }: { payload: Payload; id: string }) { + const post = await payload.findByID({ + collection: 'posts', + id, + depth: 0, + }) + + const related = await payload.find({ + collection: 'posts', + where: { + category: { equals: post.category }, + id: { not_equals: id }, + }, + limit: 5, + }) + + return ( +
+

Related Posts

+
    + {related.docs.map((doc) => ( +
  • {doc.title}
  • + ))} +
+
+ ) +} + +export default RelatedPosts +``` + +## Performance Best Practices + +### 1. Minimize Client Bundle Size + +```tsx +// ❌ BAD: Imports entire package +'use client' +import { Button } from '@payloadcms/ui' + +// ✅ GOOD: Tree-shakeable import for frontend +import { Button } from '@payloadcms/ui/elements/Button' +``` + +**Rule:** In Admin Panel UI, import from `@payloadcms/ui`. In frontend code, use specific paths. + +### 2. Optimize Re-renders + +```tsx +// ❌ BAD: Re-renders on every form change +'use client' +import { useForm } from '@payloadcms/ui' + +export function MyComponent() { + const { fields } = useForm() + // Re-renders on ANY field change +} + +// ✅ GOOD: Only re-renders when specific field changes +;('use client') +import { useFormFields } from '@payloadcms/ui' + +export function MyComponent({ path }) { + const value = useFormFields(([fields]) => fields[path]) + // Only re-renders when this field changes +} +``` + +### 3. Use Server Components When Possible + +```tsx +// ✅ GOOD: No JavaScript sent to client +async function PostCount({ payload }) { + const { totalDocs } = await payload.find({ + collection: 'posts', + limit: 0, + }) + + return

{totalDocs} posts

+} + +// Only use client components when you need: +// - State (useState, useReducer) +// - Effects (useEffect) +// - Event handlers (onClick, onChange) +// - Browser APIs (localStorage, window) +``` + +### 4. React Best Practices + +- Use React.memo() for expensive components +- Implement proper key props in lists +- Avoid inline function definitions in renders +- Use Suspense boundaries for async operations + +## Import Map + +Payload generates an import map at `app/(payload)/admin/importMap.js` that resolves all component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Override location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Type Safety + +Use Payload's TypeScript types for components: + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, +} from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = (props) => { + // Fully typed props +} +``` + +## Troubleshooting + +### "useConfig is undefined" or similar hook errors + +**Cause:** Dependency version mismatch between Payload packages. + +**Solution:** Pin all `@payloadcms/*` packages to the exact same version: + +```json +{ + "dependencies": { + "payload": "3.0.0", + "@payloadcms/ui": "3.0.0", + "@payloadcms/richtext-lexical": "3.0.0" + } +} +``` + +### Component not loading + +1. Check file path is correct (relative to baseDir) +2. Verify named export syntax: `/path/to/file#ExportName` +3. Run `payload generate:importmap` to regenerate +4. Check for TypeScript errors in component file + +## Resources + +- [Custom Components Docs](https://payloadcms.com/docs/custom-components/overview) +- [Root Components](https://payloadcms.com/docs/custom-components/root-components) +- [Custom Views](https://payloadcms.com/docs/custom-components/custom-views) +- [React Hooks](https://payloadcms.com/docs/admin/react-hooks) +- [Custom CSS](https://payloadcms.com/docs/admin/customizing-css) diff --git a/templates/_agents/rules/endpoints.md b/templates/_agents/rules/endpoints.md new file mode 100644 index 00000000000..8a2481dbe5d --- /dev/null +++ b/templates/_agents/rules/endpoints.md @@ -0,0 +1,236 @@ +--- +title: Custom Endpoints +description: Custom REST API endpoints with authentication and helpers +tags: [payload, endpoints, api, routes, webhooks] +--- + +# Payload Custom Endpoints + +## Basic Endpoint Pattern + +Custom endpoints are **not authenticated by default**. Always check `req.user`. + +```typescript +import { APIError } from 'payload' +import type { Endpoint } from 'payload' + +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} +``` + +## Route Parameters + +```typescript +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Request Body Handling + +```typescript +// Manual JSON parsing +export const createEndpoint: Endpoint = { + path: '/create', + method: 'post', + handler: async (req) => { + const data = await req.json() + + const result = await req.payload.create({ + collection: 'posts', + data, + }) + + return Response.json(result) + }, +} + +// Using helper (handles JSON + files) +import { addDataAndFileToRequest } from 'payload' + +export const uploadEndpoint: Endpoint = { + path: '/upload', + method: 'post', + handler: async (req) => { + await addDataAndFileToRequest(req) + + // req.data contains parsed body + // req.file contains uploaded file (if multipart) + + const result = await req.payload.create({ + collection: 'media', + data: req.data, + file: req.file, + }) + + return Response.json(result) + }, +} +``` + +## Query Parameters + +```typescript +export const searchEndpoint: Endpoint = { + path: '/search', + method: 'get', + handler: async (req) => { + const url = new URL(req.url) + const query = url.searchParams.get('q') + const limit = parseInt(url.searchParams.get('limit') || '10') + + const results = await req.payload.find({ + collection: 'posts', + where: { + title: { + contains: query, + }, + }, + limit, + }) + + return Response.json(results) + }, +} +``` + +## CORS Headers + +```typescript +import { headersWithCors } from 'payload' + +export const corsEndpoint: Endpoint = { + path: '/public-data', + method: 'get', + handler: async (req) => { + const data = await fetchPublicData() + + return Response.json(data, { + headers: headersWithCors({ + headers: new Headers(), + req, + }), + }) + }, +} +``` + +## Error Handling + +```typescript +import { APIError } from 'payload' + +export const validateEndpoint: Endpoint = { + path: '/validate', + method: 'post', + handler: async (req) => { + const data = await req.json() + + if (!data.email) { + throw new APIError('Email is required', 400) + } + + return Response.json({ valid: true }) + }, +} +``` + +## Endpoint Placement + +### Collection Endpoints + +Mounted at `/api/{collection-slug}/{path}`. + +```typescript +export const Orders: CollectionConfig = { + slug: 'orders', + endpoints: [ + { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + // Available at: /api/orders/:id/tracking + const orderId = req.routeParams.id + return Response.json({ orderId }) + }, + }, + ], +} +``` + +### Global Endpoints + +Mounted at `/api/globals/{global-slug}/{path}`. + +```typescript +export const Settings: GlobalConfig = { + slug: 'settings', + endpoints: [ + { + path: '/clear-cache', + method: 'post', + handler: async (req) => { + // Available at: /api/globals/settings/clear-cache + await clearCache() + return Response.json({ message: 'Cache cleared' }) + }, + }, + ], +} +``` + +### Root Endpoints + +Mounted at `/api/{path}`. + +```typescript +export default buildConfig({ + endpoints: [ + { + path: '/hello', + method: 'get', + handler: () => { + // Available at: /api/hello + return Response.json({ message: 'Hello!' }) + }, + }, + ], +}) +``` + +## Best Practices + +1. **Always check authentication** - Custom endpoints are not authenticated by default +2. **Use `req.payload` for operations** - Ensures access control and hooks execute +3. **Use helpers for common tasks** - `addDataAndFileToRequest`, `headersWithCors` +4. **Throw `APIError` for errors** - Provides consistent error responses +5. **Return Web API `Response`** - Use `Response.json()` for consistent responses +6. **Validate input** - Check required fields, validate types +7. **Log errors** - Use `req.payload.logger` for debugging diff --git a/templates/_agents/rules/field-type-guards.md b/templates/_agents/rules/field-type-guards.md new file mode 100644 index 00000000000..3514ad44993 --- /dev/null +++ b/templates/_agents/rules/field-type-guards.md @@ -0,0 +1,230 @@ +--- +title: Field Type Guards +description: Runtime field type checking and safe type narrowing +tags: [payload, typescript, type-guards, fields] +--- + +# Payload Field Type Guards + +Type guards for runtime field type checking and safe type narrowing. + +## Most Common Guards + +### fieldAffectsData + +**Most commonly used guard.** Checks if field stores data (has name and is not UI-only). + +```typescript +import { fieldAffectsData } from 'payload' + +function generateSchema(fields: Field[]) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + // Safe to access field.name + schema[field.name] = getFieldType(field) + } + }) +} + +// Filter data fields +const dataFields = fields.filter(fieldAffectsData) +``` + +### fieldHasSubFields + +Checks if field contains nested fields (group, array, row, or collapsible). + +```typescript +import { fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[]): void { + fields.forEach((field) => { + if (fieldHasSubFields(field)) { + // Safe to access field.fields + traverseFields(field.fields) + } + }) +} +``` + +### fieldIsArrayType + +Checks if field type is `'array'`. + +```typescript +import { fieldIsArrayType } from 'payload' + +if (fieldIsArrayType(field)) { + // field.type === 'array' + console.log(`Min rows: ${field.minRows}`) + console.log(`Max rows: ${field.maxRows}`) +} +``` + +## Capability Guards + +### fieldSupportsMany + +Checks if field can have multiple values (select, relationship, or upload with `hasMany`). + +```typescript +import { fieldSupportsMany } from 'payload' + +if (fieldSupportsMany(field)) { + // field.type is 'select' | 'relationship' | 'upload' + if (field.hasMany) { + console.log('Field accepts multiple values') + } +} +``` + +### fieldHasMaxDepth + +Checks if field is relationship/upload/join with numeric `maxDepth` property. + +```typescript +import { fieldHasMaxDepth } from 'payload' + +if (fieldHasMaxDepth(field)) { + // field.type is 'upload' | 'relationship' | 'join' + // AND field.maxDepth is number + const remainingDepth = field.maxDepth - currentDepth +} +``` + +### fieldIsVirtual + +Checks if field is virtual (computed or virtual relationship). + +```typescript +import { fieldIsVirtual } from 'payload' + +if (fieldIsVirtual(field)) { + // field.virtual is truthy + if (typeof field.virtual === 'string') { + console.log(`Virtual path: ${field.virtual}`) + } +} +``` + +## Type Checking Guards + +### fieldIsBlockType + +```typescript +import { fieldIsBlockType } from 'payload' + +if (fieldIsBlockType(field)) { + // field.type === 'blocks' + field.blocks.forEach((block) => { + console.log(`Block: ${block.slug}`) + }) +} +``` + +### fieldIsGroupType + +```typescript +import { fieldIsGroupType } from 'payload' + +if (fieldIsGroupType(field)) { + // field.type === 'group' + console.log(`Interface: ${field.interfaceName}`) +} +``` + +### fieldIsPresentationalOnly + +```typescript +import { fieldIsPresentationalOnly } from 'payload' + +if (fieldIsPresentationalOnly(field)) { + // field.type === 'ui' + // Skip in data operations, GraphQL schema, etc. + return +} +``` + +## Common Patterns + +### Recursive Field Traversal + +```typescript +import { fieldAffectsData, fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[], callback: (field: Field) => void) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + callback(field) + } + + if (fieldHasSubFields(field)) { + traverseFields(field.fields, callback) + } + }) +} +``` + +### Filter Data-Bearing Fields + +```typescript +import { fieldAffectsData, fieldIsPresentationalOnly, fieldIsHiddenOrDisabled } from 'payload' + +const dataFields = fields.filter( + (field) => + fieldAffectsData(field) && !fieldIsPresentationalOnly(field) && !fieldIsHiddenOrDisabled(field), +) +``` + +### Container Type Switching + +```typescript +import { fieldIsArrayType, fieldIsBlockType, fieldHasSubFields } from 'payload' + +if (fieldIsArrayType(field)) { + // Handle array-specific logic +} else if (fieldIsBlockType(field)) { + // Handle blocks-specific logic +} else if (fieldHasSubFields(field)) { + // Handle group/row/collapsible +} +``` + +### Safe Property Access + +```typescript +import { fieldSupportsMany, fieldHasMaxDepth } from 'payload' + +// With guard - safe access +if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') +} + +if (fieldHasMaxDepth(field)) { + const depth = field.maxDepth // TypeScript knows this is number +} +``` + +## All Available Guards + +| Type Guard | Checks For | Use When | +| --------------------------- | --------------------------------- | ---------------------------------------- | +| `fieldAffectsData` | Field stores data (has name) | Need to access field data or name | +| `fieldHasSubFields` | Field contains nested fields | Recursively traverse fields | +| `fieldIsArrayType` | Field is array type | Distinguish arrays from other containers | +| `fieldIsBlockType` | Field is blocks type | Handle blocks-specific logic | +| `fieldIsGroupType` | Field is group type | Handle group-specific logic | +| `fieldSupportsMany` | Field can have multiple values | Check for `hasMany` support | +| `fieldHasMaxDepth` | Field supports depth control | Control relationship/upload/join depth | +| `fieldIsPresentationalOnly` | Field is UI-only | Exclude from data operations | +| `fieldIsSidebar` | Field positioned in sidebar | Separate sidebar rendering | +| `fieldIsID` | Field name is 'id' | Special ID field handling | +| `fieldIsHiddenOrDisabled` | Field is hidden or disabled | Filter from UI operations | +| `fieldShouldBeLocalized` | Field needs localization | Proper locale table checks | +| `fieldIsVirtual` | Field is virtual | Skip in database transforms | +| `tabHasName` | Tab is named (stores data) | Distinguish named vs unnamed tabs | +| `groupHasName` | Group is named (stores data) | Distinguish named vs unnamed groups | +| `optionIsObject` | Option is `{label, value}` | Access option properties safely | +| `optionsAreObjects` | All options are objects | Batch option processing | +| `optionIsValue` | Option is string value | Handle string options | +| `valueIsValueWithRelation` | Value is polymorphic relationship | Handle polymorphic relationships | diff --git a/templates/_agents/rules/fields.md b/templates/_agents/rules/fields.md new file mode 100644 index 00000000000..8468e41f599 --- /dev/null +++ b/templates/_agents/rules/fields.md @@ -0,0 +1,317 @@ +--- +title: Fields +description: Field types, patterns, and configurations +tags: [payload, fields, validation, conditional] +--- + +# Payload CMS Fields + +## Common Field Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## Field Types + +### Text Field + +```typescript +{ + name: 'title', + type: 'text', + required: true, + unique: true, + minLength: 5, + maxLength: 100, + index: true, + localized: true, + defaultValue: 'Default Title', + validate: (value) => Boolean(value) || 'Required', + admin: { + placeholder: 'Enter title...', + position: 'sidebar', + condition: (data) => data.showTitle === true, + }, +} +``` + +### Rich Text (Lexical) + +```typescript +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { HeadingFeature, LinkFeature } from '@payloadcms/richtext-lexical' + +{ + name: 'content', + type: 'richText', + required: true, + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + HeadingFeature({ + enabledHeadingSizes: ['h1', 'h2', 'h3'], + }), + LinkFeature({ + enabledCollections: ['posts', 'pages'], + }), + ], + }), +} +``` + +### Relationship + +```typescript +// Single relationship +{ + name: 'author', + type: 'relationship', + relationTo: 'users', + required: true, + maxDepth: 2, +} + +// Multiple relationships (hasMany) +{ + name: 'categories', + type: 'relationship', + relationTo: 'categories', + hasMany: true, + filterOptions: { + active: { equals: true }, + }, +} + +// Polymorphic relationship +{ + name: 'relatedContent', + type: 'relationship', + relationTo: ['posts', 'pages'], + hasMany: true, +} +``` + +### Array + +```typescript +{ + name: 'slides', + type: 'array', + minRows: 2, + maxRows: 10, + labels: { + singular: 'Slide', + plural: 'Slides', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'image', + type: 'upload', + relationTo: 'media', + }, + ], + admin: { + initCollapsed: true, + }, +} +``` + +### Blocks + +```typescript +import type { Block } from 'payload' + +const HeroBlock: Block = { + slug: 'hero', + interfaceName: 'HeroBlock', + fields: [ + { + name: 'heading', + type: 'text', + required: true, + }, + { + name: 'background', + type: 'upload', + relationTo: 'media', + }, + ], +} + +const ContentBlock: Block = { + slug: 'content', + fields: [ + { + name: 'text', + type: 'richText', + }, + ], +} + +{ + name: 'layout', + type: 'blocks', + blocks: [HeroBlock, ContentBlock], +} +``` + +### Select + +```typescript +{ + name: 'status', + type: 'select', + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + ], + defaultValue: 'draft', + required: true, +} + +// Multiple select +{ + name: 'tags', + type: 'select', + hasMany: true, + options: ['tech', 'news', 'sports'], +} +``` + +### Upload + +```typescript +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + required: true, + filterOptions: { + mimeType: { contains: 'image' }, + }, +} +``` + +### Point (Geolocation) + +```typescript +{ + name: 'location', + type: 'point', + label: 'Location', + required: true, +} + +// Query by distance +const nearbyLocations = await payload.find({ + collection: 'stores', + where: { + location: { + near: [10, 20], // [longitude, latitude] + maxDistance: 5000, // in meters + minDistance: 1000, + }, + }, +}) +``` + +### Join Fields (Reverse Relationships) + +```typescript +// From Users collection - show user's orders +{ + name: 'orders', + type: 'join', + collection: 'orders', + on: 'customer', // The field in 'orders' that references this user +} +``` + +### Tabs & Groups + +```typescript +// Tabs +{ + type: 'tabs', + tabs: [ + { + label: 'Content', + fields: [ + { name: 'title', type: 'text' }, + { name: 'body', type: 'richText' }, + ], + }, + { + label: 'SEO', + fields: [ + { name: 'metaTitle', type: 'text' }, + { name: 'metaDescription', type: 'textarea' }, + ], + }, + ], +} + +// Group (named) +{ + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], +} +``` + +## Validation + +```typescript +{ + name: 'email', + type: 'email', + validate: (value, { operation, data, siblingData }) => { + if (operation === 'create' && !value) { + return 'Email is required' + } + if (value && !value.includes('@')) { + return 'Invalid email format' + } + return true + }, +} +``` diff --git a/templates/_agents/rules/hooks.md b/templates/_agents/rules/hooks.md new file mode 100644 index 00000000000..1f168f9eaeb --- /dev/null +++ b/templates/_agents/rules/hooks.md @@ -0,0 +1,175 @@ +--- +title: Hooks +description: Collection hooks, field hooks, and context patterns +tags: [payload, hooks, lifecycle, context] +--- + +# Payload CMS Hooks + +## Collection Hooks + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Field Hooks + +```typescript +import type { FieldHook } from 'payload' + +const beforeValidateHook: FieldHook = ({ value }) => { + return value.trim().toLowerCase() +} + +const afterReadHook: FieldHook = ({ value, req }) => { + // Hide email from non-admins + if (!req.user?.roles?.includes('admin')) { + return value.replace(/(.{2})(.*)(@.*)/, '$1***$3') + } + return value +} + +{ + name: 'email', + type: 'email', + hooks: { + beforeValidate: [beforeValidateHook], + afterRead: [afterReadHook], + }, +} +``` + +## Hook Context + +Share data between hooks or control hook behavior using request context: + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + beforeChange: [ + async ({ context }) => { + context.expensiveData = await fetchExpensiveData() + }, + ], + afterChange: [ + async ({ context, doc }) => { + // Reuse from previous hook + await processData(doc, context.expensiveData) + }, + ], + }, +} +``` + +## Next.js Revalidation Pattern + +```typescript +import type { CollectionAfterChangeHook } from 'payload' +import { revalidatePath } from 'next/cache' + +export const revalidatePage: CollectionAfterChangeHook = ({ + doc, + previousDoc, + req: { payload, context }, +}) => { + if (!context.disableRevalidate) { + if (doc._status === 'published') { + const path = doc.slug === 'home' ? '/' : `/${doc.slug}` + payload.logger.info(`Revalidating page at path: ${path}`) + revalidatePath(path) + } + + // Revalidate old path if unpublished + if (previousDoc?._status === 'published' && doc._status !== 'published') { + const oldPath = previousDoc.slug === 'home' ? '/' : `/${previousDoc.slug}` + revalidatePath(oldPath) + } + } + return doc +} +``` + +## Date Field Auto-Set + +```typescript +{ + name: 'publishedOn', + type: 'date', + hooks: { + beforeChange: [ + ({ siblingData, value }) => { + if (siblingData._status === 'published' && !value) { + return new Date() + } + return value + }, + ], + }, +} +``` + +## Best Practices + +- Use `beforeValidate` for data formatting +- Use `beforeChange` for business logic +- Use `afterChange` for side effects +- Use `afterRead` for computed fields +- Store expensive operations in `context` +- Pass `req` to nested operations for transaction safety +- Use context flags to prevent infinite loops diff --git a/templates/_agents/rules/payload-overview.md b/templates/_agents/rules/payload-overview.md new file mode 100644 index 00000000000..290c47822ab --- /dev/null +++ b/templates/_agents/rules/payload-overview.md @@ -0,0 +1,126 @@ +--- +title: Payload CMS Overview +description: Core principles and quick reference for Payload CMS development +tags: [payload, overview, quickstart] +--- + +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Quick Reference + +| Task | Solution | +| --------------------- | ---------------------------------- | +| Auto-generate slugs | `slugField()` | +| Restrict by user | Access control with query | +| Local API user ops | `user` + `overrideAccess: false` | +| Draft/publish | `versions: { drafts: true }` | +| Computed fields | `virtual: true` with afterRead | +| Conditional fields | `admin.condition` | +| Custom validation | `validate` function | +| Filter relationships | `filterOptions` on field | +| Select fields | `select` parameter | +| Auto-set dates | beforeChange hook | +| Prevent loops | `req.context` check | +| Cascading deletes | beforeDelete hook | +| Geospatial queries | `point` field with `near`/`within` | +| Reverse relationships | `join` field type | +| Query relationships | Nested property syntax | +| Complex queries | AND/OR logic | +| Transactions | Pass `req` to operations | +| Background jobs | Jobs queue with tasks | +| Custom routes | Collection custom endpoints | +| Cloud storage | Storage adapter plugins | +| Multi-language | `localization` + `localized: true` | + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/_agents/rules/plugin-development.md b/templates/_agents/rules/plugin-development.md new file mode 100644 index 00000000000..d92bb12fb40 --- /dev/null +++ b/templates/_agents/rules/plugin-development.md @@ -0,0 +1,323 @@ +--- +title: Plugin Development +description: Creating Payload CMS plugins with TypeScript patterns +tags: [payload, plugins, architecture, patterns] +--- + +# Payload Plugin Development + +## Plugin Architecture + +Plugins are functions that receive configuration options and return a function that transforms the Payload config: + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + enabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + // Transform config here + }) +``` + +**Key Pattern:** Double arrow function (currying) + +- First function: Accepts plugin options, returns plugin function +- Second function: Accepts Payload config, returns modified config + +## Adding Fields to Collections + +```typescript +export const seoPlugin = + (options: { collections?: string[] }): Plugin => + (config: Config): Config => { + const seoFields: Field[] = [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], + }, + ] + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...seoFields], + } + } + return collection + }), + } + } +``` + +## Adding New Collections + +```typescript +export const redirectsPlugin = + (options: { overrides?: Partial }): Plugin => + (config: Config): Config => { + const redirectsCollection: CollectionConfig = { + slug: 'redirects', + access: { read: () => true }, + fields: [ + { name: 'from', type: 'text', required: true, unique: true }, + { name: 'to', type: 'text', required: true }, + ], + ...options.overrides, + } + + return { + ...config, + collections: [...(config.collections || []), redirectsCollection], + } + } +``` + +## Adding Hooks + +```typescript +const resaveChildrenHook: CollectionAfterChangeHook = async ({ doc, req, operation }) => { + if (operation === 'update') { + const children = await req.payload.find({ + collection: 'pages', + where: { parent: { equals: doc.id } }, + }) + + for (const child of children.docs) { + await req.payload.update({ + collection: 'pages', + id: child.id, + data: child, + }) + } + } + return doc +} + +export const nestedDocsPlugin = + (options: { collections: string[] }): Plugin => + (config: Config): Config => ({ + ...config, + collections: (config.collections || []).map((collection) => { + if (options.collections.includes(collection.slug)) { + return { + ...collection, + hooks: { + ...(collection.hooks || {}), + afterChange: [resaveChildrenHook, ...(collection.hooks?.afterChange || [])], + }, + } + } + return collection + }), + }) +``` + +## Adding Root-Level Endpoints + +```typescript +export const seoPlugin = + (options: { generateTitle?: (doc: any) => string }): Plugin => + (config: Config): Config => { + const generateTitleEndpoint: Endpoint = { + path: '/plugin-seo/generate-title', + method: 'post', + handler: async (req) => { + const data = await req.json?.() + const result = options.generateTitle ? options.generateTitle(data.doc) : '' + return Response.json({ result }) + }, + } + + return { + ...config, + endpoints: [...(config.endpoints ?? []), generateTitleEndpoint], + } + } +``` + +## Field Overrides with Defaults + +```typescript +type FieldsOverride = (args: { defaultFields: Field[] }) => Field[] + +interface PluginConfig { + collections?: string[] + fields?: FieldsOverride +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const defaultFields: Field[] = [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ] + + const fields = + options.fields && typeof options.fields === 'function' + ? options.fields({ defaultFields }) + : defaultFields + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...fields], + } + } + return collection + }), + } + } +``` + +## Disable Plugin Pattern + +```typescript +interface PluginConfig { + disabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + // Always add collections/fields for database schema consistency + if (!config.collections) { + config.collections = [] + } + + config.collections.push({ + slug: 'plugin-collection', + fields: [{ name: 'title', type: 'text' }], + }) + + // If disabled, return early but keep schema changes + if (options.disabled) { + return config + } + + // Add endpoints, hooks, components only when enabled + config.endpoints = [ + ...(config.endpoints ?? []), + { + path: '/my-endpoint', + method: 'get', + handler: async () => Response.json({ message: 'Hello' }), + }, + ] + + return config + } +``` + +## Admin Components + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + if (!config.admin) config.admin = {} + if (!config.admin.components) config.admin.components = {} + if (!config.admin.components.beforeDashboard) { + config.admin.components.beforeDashboard = [] + } + + // Add client component + config.admin.components.beforeDashboard.push('my-plugin-name/client#BeforeDashboardClient') + + // Add server component (RSC) + config.admin.components.beforeDashboard.push('my-plugin-name/rsc#BeforeDashboardServer') + + return config + } +``` + +## onInit Hook + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const incomingOnInit = config.onInit + + config.onInit = async (payload) => { + // IMPORTANT: Call existing onInit first + if (incomingOnInit) await incomingOnInit(payload) + + // Plugin initialization + payload.logger.info('Plugin initialized') + + // Example: Seed data + const { totalDocs } = await payload.count({ + collection: 'plugin-collection', + where: { id: { equals: 'seeded-by-plugin' } }, + }) + + if (totalDocs === 0) { + await payload.create({ + collection: 'plugin-collection', + data: { id: 'seeded-by-plugin' }, + }) + } + } + + return config + } +``` + +## Best Practices + +### Preserve Existing Config + +```typescript +// ✅ Good +collections: [...(config.collections || []), newCollection] + +// ❌ Bad +collections: [newCollection] +``` + +### Respect User Overrides + +```typescript +const collection: CollectionConfig = { + slug: 'redirects', + fields: defaultFields, + ...options.overrides, // User overrides last +} +``` + +### Hook Composition + +```typescript +hooks: { + ...collection.hooks, + afterChange: [ + myHook, + ...(collection.hooks?.afterChange || []), + ], +} +``` + +### Type Safety + +```typescript +import type { Config, Plugin, CollectionConfig, Field } from 'payload' +``` diff --git a/templates/_agents/rules/queries.md b/templates/_agents/rules/queries.md new file mode 100644 index 00000000000..4920ec85f09 --- /dev/null +++ b/templates/_agents/rules/queries.md @@ -0,0 +1,223 @@ +--- +title: Queries +description: Local API, REST, and GraphQL query patterns +tags: [payload, queries, local-api, rest, graphql] +--- + +# Payload CMS Queries + +## Query Operators + +```typescript +// Equals +{ color: { equals: 'blue' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater/less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In/not in +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (point fields) +{ location: { near: [10, 20, 5000] } } // [lng, lat, maxDistance] +``` + +## AND/OR Logic + +```typescript +{ + or: [ + { color: { equals: 'mint' } }, + { + and: [ + { color: { equals: 'white' } }, + { featured: { equals: false } }, + ], + }, + ], +} +``` + +## Nested Properties + +```typescript +{ + 'author.role': { equals: 'editor' }, + 'meta.featured': { exists: true }, +} +``` + +## Local API + +```typescript +// Find documents +const posts = await payload.find({ + collection: 'posts', + where: { + status: { equals: 'published' }, + 'author.name': { contains: 'john' }, + }, + depth: 2, // Populate relationships + limit: 10, + page: 1, + sort: '-createdAt', + locale: 'en', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const post = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { + status: 'published', + }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) + +// Count +const count = await payload.count({ + collection: 'posts', + where: { + status: { equals: 'published' }, + }, +}) +``` + +## Access Control in Local API + +**CRITICAL**: Local API bypasses access control by default (`overrideAccess: true`). + +```typescript +// ❌ WRONG: User is passed but access control is bypassed +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + // Result: Operation runs with ADMIN privileges +}) + +// ✅ CORRECT: Respects user's access control permissions +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + overrideAccess: false, // Required to enforce access control +}) + +// Administrative operation (intentionally bypass access control) +const allPosts = await payload.find({ + collection: 'posts', + // No user parameter, overrideAccess defaults to true +}) +``` + +**When to use `overrideAccess: false`:** + +- Performing operations on behalf of a user +- Testing access control logic +- API routes that should respect user permissions + +## REST API + +```typescript +import { stringify } from 'qs-esm' + +const query = { + status: { equals: 'published' }, +} + +const queryString = stringify( + { + where: query, + depth: 2, + limit: 10, + }, + { addQueryPrefix: true }, +) + +const response = await fetch(`https://api.example.com/api/posts${queryString}`) +const data = await response.json() +``` + +### REST Endpoints + +``` +GET /api/{collection} - Find documents +GET /api/{collection}/{id} - Find by ID +POST /api/{collection} - Create +PATCH /api/{collection}/{id} - Update +DELETE /api/{collection}/{id} - Delete +GET /api/{collection}/count - Count documents + +GET /api/globals/{slug} - Get global +POST /api/globals/{slug} - Update global +``` + +## GraphQL + +```graphql +query { + Posts(where: { status: { equals: published } }, limit: 10, sort: "-createdAt") { + docs { + id + title + author { + name + } + } + totalDocs + hasNextPage + } +} + +mutation { + createPost(data: { title: "New Post", status: draft }) { + id + title + } +} +``` + +## Performance Best Practices + +- Set `maxDepth` on relationships to prevent over-fetching +- Use `select` to limit returned fields +- Index frequently queried fields +- Use `virtual` fields for computed data +- Cache expensive operations in hook `context` diff --git a/templates/_agents/rules/security-critical.mdc b/templates/_agents/rules/security-critical.mdc new file mode 100644 index 00000000000..adf5d9e225d --- /dev/null +++ b/templates/_agents/rules/security-critical.mdc @@ -0,0 +1,122 @@ +--- +title: Critical Security Patterns +description: The three most important security patterns in Payload CMS +tags: [payload, security, critical, access-control, transactions, hooks] +priority: high +--- + +# CRITICAL SECURITY PATTERNS + +These are the three most critical security patterns that MUST be followed in every Payload CMS project. + +## 1. Local API Access Control (MOST IMPORTANT) + +**By default, Local API operations bypass ALL access control**, even when passing a user. + +```typescript +// ❌ SECURITY BUG: Passes user but ignores their permissions +await payload.find({ + collection: 'posts', + user: someUser, // Access control is BYPASSED! +}) + +// ✅ SECURE: Actually enforces the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED for access control +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**When to use each:** + +- `overrideAccess: true` (default) - Server-side operations you trust (cron jobs, system tasks) +- `overrideAccess: false` - When operating on behalf of a user (API routes, webhooks) + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +## 2. Transaction Safety in Hooks + +**Nested operations in hooks without `req` break transaction atomicity.** + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ] +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ] +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +## 3. Prevent Infinite Hook Loops + +**Hooks triggering operations that trigger the same hooks create infinite loops.** + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ] +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ] +} +``` + +**Rule**: Use `req.context` flags to prevent hook loops diff --git a/templates/blank/.cursor/rules/access-control-advanced.md b/templates/blank/.cursor/rules/access-control-advanced.md new file mode 100644 index 00000000000..68f52fd1287 --- /dev/null +++ b/templates/blank/.cursor/rules/access-control-advanced.md @@ -0,0 +1,519 @@ +--- +title: Access Control - Advanced Patterns +description: Context-aware, time-based, subscription-based access, factory functions, templates +tags: [payload, access-control, security, advanced, performance] +priority: high +--- + +# Advanced Access Control Patterns + +Advanced access control patterns including context-aware access, time-based restrictions, factory functions, and production templates. + +## Context-Aware Access Patterns + +### Locale-Specific Access + +```typescript +import type { Access } from 'payload' + +export const localeSpecificAccess: Access = ({ req: { user, locale } }) => { + // Authenticated users can access all locales + if (user) return true + + // Public users can only access English content + if (locale === 'en') return true + + return false +} +``` + +### Device-Specific Access + +```typescript +export const mobileOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return /mobile|android|iphone/i.test(userAgent) +} + +export const desktopOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return !/mobile|android|iphone/i.test(userAgent) +} +``` + +### IP-Based Access + +```typescript +export const restrictedIpAccess = (allowedIps: string[]): Access => { + return ({ req: { headers } }) => { + const ip = headers?.get('x-forwarded-for') || headers?.get('x-real-ip') + return allowedIps.includes(ip || '') + } +} + +// Usage +const internalIps = ['192.168.1.0/24', '10.0.0.5'] + +export const InternalDocs: CollectionConfig = { + slug: 'internal-docs', + access: { + read: restrictedIpAccess(internalIps), + }, +} +``` + +## Time-Based Access Patterns + +### Today's Records Only + +```typescript +export const todayOnlyAccess: Access = ({ req: { user } }) => { + if (!user) return false + + const now = new Date() + const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000) + + return { + createdAt: { + greater_than_equal: startOfDay.toISOString(), + less_than: endOfDay.toISOString(), + }, + } +} +``` + +### Recent Records (Last N Days) + +```typescript +export const recentRecordsAccess = (days: number): Access => { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - days) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} + +// Usage: Users see only last 30 days, admins see all +export const Logs: CollectionConfig = { + slug: 'logs', + access: { + read: recentRecordsAccess(30), + }, +} +``` + +### Scheduled Content (Publish Date Range) + +```typescript +export const scheduledContentAccess: Access = ({ req: { user } }) => { + // Editors see all content + if (user?.roles?.includes('admin') || user?.roles?.includes('editor')) { + return true + } + + const now = new Date().toISOString() + + // Public sees only content within publish window + return { + and: [ + { publishDate: { less_than_equal: now } }, + { + or: [{ unpublishDate: { exists: false } }, { unpublishDate: { greater_than: now } }], + }, + ], + } +} +``` + +## Subscription-Based Access + +### Active Subscription Required + +```typescript +export const activeSubscriptionAccess: Access = async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + return subscription?.status === 'active' + } catch { + return false + } +} +``` + +### Subscription Tier-Based Access + +```typescript +export const tierBasedAccess = (requiredTier: string): Access => { + const tierHierarchy = ['free', 'basic', 'pro', 'enterprise'] + + return async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + if (subscription?.status !== 'active') return false + + const userTierIndex = tierHierarchy.indexOf(subscription.tier) + const requiredTierIndex = tierHierarchy.indexOf(requiredTier) + + return userTierIndex >= requiredTierIndex + } catch { + return false + } + } +} + +// Usage +export const EnterpriseFeatures: CollectionConfig = { + slug: 'enterprise-features', + access: { + read: tierBasedAccess('enterprise'), + }, +} +``` + +## Factory Functions + +### createRoleBasedAccess + +```typescript +export function createRoleBasedAccess(roles: string[]): Access { + return ({ req: { user } }) => { + if (!user) return false + return roles.some((role) => user.roles?.includes(role)) + } +} + +// Usage +const adminOrEditor = createRoleBasedAccess(['admin', 'editor']) +const moderatorAccess = createRoleBasedAccess(['admin', 'moderator']) +``` + +### createOrgScopedAccess + +```typescript +export function createOrgScopedAccess(allowAdmin = true): Access { + return ({ req: { user } }) => { + if (!user) return false + if (allowAdmin && user.roles?.includes('admin')) return true + + return { + organizationId: { in: user.organizationIds || [] }, + } + } +} + +// Usage +const orgScoped = createOrgScopedAccess() // Admins bypass +const strictOrgScoped = createOrgScopedAccess(false) // Admins also scoped +``` + +### createTeamBasedAccess + +```typescript +export function createTeamBasedAccess(teamField = 'teamId'): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + [teamField]: { in: user.teamIds || [] }, + } + } +} +``` + +### createTimeLimitedAccess + +```typescript +export function createTimeLimitedAccess(daysAccess: number): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - daysAccess) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} +``` + +## Configuration Templates + +### Public + Authenticated Collection + +```typescript +export const PublicAuthCollection: CollectionConfig = { + slug: 'posts', + access: { + // Only admins/editors can create + create: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Authenticated users see all, public sees only published + read: ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } + }, + + // Only admins/editors can update + update: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Only admins can delete + delete: ({ req: { user } }) => { + return user?.roles?.includes('admin') || false + }, + }, + versions: { + drafts: true, + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'content', type: 'richText', required: true }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], +} +``` + +### Self-Service Collection + +```typescript +export const SelfServiceCollection: CollectionConfig = { + slug: 'users', + auth: true, + access: { + // Admins can create users + create: ({ req: { user } }) => user?.roles?.includes('admin') || false, + + // Anyone can read user profiles + read: () => true, + + // Users can update self, admins can update anyone + update: ({ req: { user }, id }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + return user.id === id + }, + + // Only admins can delete + delete: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + fields: [ + { name: 'name', type: 'text', required: true }, + { name: 'email', type: 'email', required: true }, + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + access: { + // Only admins can read/update roles + read: ({ req: { user } }) => user?.roles?.includes('admin') || false, + update: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + }, + ], +} +``` + +## Performance Considerations + +### Avoid Async Operations in Hot Paths + +```typescript +// ❌ Slow: Multiple sequential async calls +export const slowAccess: Access = async ({ req: { user } }) => { + const org = await req.payload.findByID({ collection: 'orgs', id: user.orgId }) + const team = await req.payload.findByID({ collection: 'teams', id: user.teamId }) + const subscription = await req.payload.findByID({ collection: 'subs', id: user.subId }) + + return org.active && team.active && subscription.active +} + +// ✅ Fast: Use query constraints or cache in context +export const fastAccess: Access = ({ req: { user, context } }) => { + // Cache expensive lookups + if (!context.orgStatus) { + context.orgStatus = checkOrgStatus(user.orgId) + } + + return context.orgStatus +} +``` + +### Query Constraint Optimization + +```typescript +// ❌ Avoid: Non-indexed fields in constraints +export const slowQuery: Access = () => ({ + 'metadata.internalCode': { equals: 'ABC123' }, // Slow if not indexed +}) + +// ✅ Better: Use indexed fields +export const fastQuery: Access = () => ({ + status: { equals: 'active' }, // Indexed field + organizationId: { in: ['org1', 'org2'] }, // Indexed field +}) +``` + +### Field Access on Large Arrays + +```typescript +// ❌ Slow: Complex access on array fields +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: async ({ req }) => { + // Async call runs for EVERY array item + const result = await expensiveCheck() + return result + }, + }, + }, + ], +} + +// ✅ Fast: Simple checks or cache result +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: ({ req: { user }, context }) => { + // Cache once, reuse for all items + if (context.canReadSecret === undefined) { + context.canReadSecret = user?.roles?.includes('admin') + } + return context.canReadSecret + }, + }, + }, + ], +} +``` + +### Avoid N+1 Queries + +```typescript +// ❌ N+1 Problem: Query per access check +export const n1Access: Access = async ({ req, id }) => { + // Runs for EACH document in list + const doc = await req.payload.findByID({ collection: 'docs', id }) + return doc.isPublic +} + +// ✅ Better: Use query constraint to filter at DB level +export const efficientAccess: Access = () => { + return { isPublic: { equals: true } } +} +``` + +## Debugging Tips + +### Log Access Check Execution + +```typescript +export const debugAccess: Access = ({ req: { user }, id }) => { + console.log('Access check:', { + userId: user?.id, + userRoles: user?.roles, + docId: id, + timestamp: new Date().toISOString(), + }) + return true +} +``` + +### Verify Arguments Availability + +```typescript +export const checkArgsAccess: Access = (args) => { + console.log('Available arguments:', { + hasReq: 'req' in args, + hasUser: args.req?.user ? 'yes' : 'no', + hasId: args.id ? 'provided' : 'undefined', + hasData: args.data ? 'provided' : 'undefined', + }) + return true +} +``` + +### Test Access Without User + +```typescript +// In test/development +const testAccess = await payload.find({ + collection: 'posts', + overrideAccess: false, // Enforce access control + user: undefined, // Simulate no user +}) + +console.log('Public access result:', testAccess.docs.length) +``` + +## Best Practices + +1. **Default Deny**: Start with restrictive access, gradually add permissions +2. **Type Guards**: Use TypeScript for user type safety +3. **Validate Data**: Never trust frontend-provided IDs or data +4. **Async for Critical Checks**: Use async operations for important security decisions +5. **Consistent Logic**: Apply same rules at field and collection levels +6. **Test Edge Cases**: Test with no user, wrong user, admin user scenarios +7. **Monitor Access**: Log failed access attempts for security review +8. **Regular Audit**: Review access rules quarterly or after major changes +9. **Cache Wisely**: Use `req.context` for expensive operations +10. **Document Intent**: Add comments explaining complex access rules +11. **Avoid Secrets in Client**: Never expose sensitive logic to client-side +12. **Handle Errors Gracefully**: Access functions should return `false` on error, not throw +13. **Test Local API**: Remember to set `overrideAccess: false` when testing +14. **Consider Performance**: Measure impact of async operations +15. **Principle of Least Privilege**: Grant minimum access required + +## Performance Summary + +**Minimize Async Operations**: Use query constraints over async lookups when possible + +**Cache Expensive Checks**: Store results in `req.context` for reuse + +**Index Query Fields**: Ensure fields in query constraints are indexed + +**Avoid Complex Logic in Array Fields**: Simple boolean checks preferred + +**Use Query Constraints**: Let database filter rather than loading all records diff --git a/templates/blank/.cursor/rules/access-control.md b/templates/blank/.cursor/rules/access-control.md new file mode 100644 index 00000000000..7b9a0a4ba5c --- /dev/null +++ b/templates/blank/.cursor/rules/access-control.md @@ -0,0 +1,225 @@ +--- +title: Access Control +description: Collection, field, and global access control patterns +tags: [payload, access-control, security, permissions, rbac] +--- + +# Payload CMS Access Control + +## Access Control Layers + +1. **Collection-Level**: Controls operations on entire documents (create, read, update, delete, admin) +2. **Field-Level**: Controls access to individual fields (create, read, update) +3. **Global-Level**: Controls access to global documents (read, update) + +## Collection Access Control + +```typescript +import type { Access } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + // Boolean: Only authenticated users can create + create: ({ req: { user } }) => Boolean(user), + + // Query constraint: Public sees published, users see all + read: ({ req: { user } }) => { + if (user) return true + return { status: { equals: 'published' } } + }, + + // User-specific: Admins or document owner + update: ({ req: { user }, id }) => { + if (user?.roles?.includes('admin')) return true + return { author: { equals: user?.id } } + }, + + // Async: Check related data + delete: async ({ req, id }) => { + const hasComments = await req.payload.count({ + collection: 'comments', + where: { post: { equals: id } }, + }) + return hasComments === 0 + }, + }, +} +``` + +## Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Row-Level Security + +```typescript +// Organization-scoped access +export const organizationScoped: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + + // Users see only their organization's data + return { + organization: { + equals: user?.organization, + }, + } +} + +// Team-based access +export const teamMemberAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + 'team.members': { + contains: user.id, + }, + } +} +``` + +## Field Access Control + +**Field access ONLY returns boolean** (no query constraints). + +```typescript +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +## RBAC Pattern + +Payload does NOT provide a roles system by default. Add a `roles` field to your auth collection: + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Multi-Tenant Access Control + +```typescript +interface User { + id: string + tenantId: string + roles?: string[] +} + +const tenantAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('super-admin')) return true + + return { + tenant: { + equals: (user as User).tenantId, + }, + } +} + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + create: tenantAccess, + read: tenantAccess, + update: tenantAccess, + delete: tenantAccess, + }, + fields: [ + { + name: 'tenant', + type: 'text', + required: true, + access: { + update: ({ req: { user } }) => user?.roles?.includes('super-admin'), + }, + hooks: { + beforeChange: [ + ({ req, operation, value }) => { + if (operation === 'create' && !value) { + return (req.user as User)?.tenantId + } + return value + }, + ], + }, + }, + ], +} +``` + +## Important Notes + +1. **Local API Default**: Access control is **skipped by default** in Local API (`overrideAccess: true`). When passing a `user` parameter, you must set `overrideAccess: false`: + +```typescript +// ❌ WRONG: Passes user but bypasses access control +await payload.find({ + collection: 'posts', + user: someUser, +}) + +// ✅ CORRECT: Respects the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // Required to enforce access control +}) +``` + +2. **Field Access Limitations**: Field-level access does NOT support query constraints - only boolean returns. + +3. **Admin Panel Visibility**: The `admin` access control determines if a collection appears in the admin panel for a user. diff --git a/templates/blank/.cursor/rules/adapters.md b/templates/blank/.cursor/rules/adapters.md new file mode 100644 index 00000000000..49b8b3367fc --- /dev/null +++ b/templates/blank/.cursor/rules/adapters.md @@ -0,0 +1,209 @@ +--- +title: Database Adapters & Transactions +description: Database adapters, storage, email, and transaction patterns +tags: [payload, database, mongodb, postgres, sqlite, transactions] +--- + +# Payload CMS Adapters + +## Database Adapters + +### MongoDB + +```typescript +import { mongooseAdapter } from '@payloadcms/db-mongodb' + +export default buildConfig({ + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +### Postgres + +```typescript +import { postgresAdapter } from '@payloadcms/db-postgres' + +export default buildConfig({ + db: postgresAdapter({ + pool: { + connectionString: process.env.DATABASE_URI, + }, + push: false, // Don't auto-push schema changes + migrationDir: './migrations', + }), +}) +``` + +### SQLite + +```typescript +import { sqliteAdapter } from '@payloadcms/db-sqlite' + +export default buildConfig({ + db: sqliteAdapter({ + client: { + url: 'file:./payload.db', + }, + transactionOptions: {}, // Enable transactions (disabled by default) + }), +}) +``` + +## Transactions + +Payload automatically uses transactions for all-or-nothing database operations. + +### Threading req Through Operations + +**CRITICAL**: When performing nested operations in hooks, always pass `req` to maintain transaction context. + +```typescript +// ✅ CORRECT: Thread req through nested operations +const resaveChildren: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + // Find children - pass req + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + req, // Maintains transaction context + }) + + // Update each child - pass req + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + req, // Same transaction as parent operation + }) + } +} + +// ❌ WRONG: Missing req breaks transaction +const brokenHook: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + // Missing req - separate transaction or no transaction + }) + + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + // Missing req - if parent operation fails, these updates persist + }) + } +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +### Manual Transaction Control + +```typescript +const transactionID = await payload.db.beginTransaction() +try { + await payload.create({ + collection: 'orders', + data: orderData, + req: { transactionID }, + }) + await payload.update({ + collection: 'inventory', + id: itemId, + data: { stock: newStock }, + req: { transactionID }, + }) + await payload.db.commitTransaction(transactionID) +} catch (error) { + await payload.db.rollbackTransaction(transactionID) + throw error +} +``` + +## Storage Adapters + +Available storage adapters: + +- **@payloadcms/storage-s3** - AWS S3 +- **@payloadcms/storage-azure** - Azure Blob Storage +- **@payloadcms/storage-gcs** - Google Cloud Storage +- **@payloadcms/storage-r2** - Cloudflare R2 +- **@payloadcms/storage-vercel-blob** - Vercel Blob +- **@payloadcms/storage-uploadthing** - Uploadthing + +### AWS S3 + +```typescript +import { s3Storage } from '@payloadcms/storage-s3' + +export default buildConfig({ + plugins: [ + s3Storage({ + collections: { + media: true, + }, + bucket: process.env.S3_BUCKET, + config: { + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + region: process.env.S3_REGION, + }, + }), + ], +}) +``` + +## Email Adapters + +### Nodemailer (SMTP) + +```typescript +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' + +export default buildConfig({ + email: nodemailerAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + transportOptions: { + host: process.env.SMTP_HOST, + port: 587, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }, + }), +}) +``` + +### Resend + +```typescript +import { resendAdapter } from '@payloadcms/email-resend' + +export default buildConfig({ + email: resendAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + apiKey: process.env.RESEND_API_KEY, + }), +}) +``` + +## Important Notes + +1. **MongoDB Transactions**: Require replica set configuration +2. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +3. **Pass req**: Always pass `req` to nested operations in hooks for transaction safety +4. **Point Fields**: Not supported in SQLite diff --git a/templates/blank/.cursor/rules/collections.md b/templates/blank/.cursor/rules/collections.md new file mode 100644 index 00000000000..af625108e60 --- /dev/null +++ b/templates/blank/.cursor/rules/collections.md @@ -0,0 +1,171 @@ +--- +title: Collections +description: Collection configurations and patterns +tags: [payload, collections, auth, upload, drafts] +--- + +# Payload CMS Collections + +## Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +## Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Upload Collection + +```typescript +export const Media: CollectionConfig = { + slug: 'media', + upload: { + staticDir: 'media', + mimeTypes: ['image/*'], + imageSizes: [ + { + name: 'thumbnail', + width: 400, + height: 300, + position: 'centre', + }, + { + name: 'card', + width: 768, + height: 1024, + }, + ], + adminThumbnail: 'thumbnail', + focalPoint: true, + crop: true, + }, + access: { + read: () => true, + }, + fields: [ + { + name: 'alt', + type: 'text', + required: true, + }, + ], +} +``` + +## Versioning & Drafts + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} +``` + +### Draft API Usage + +```typescript +// Create draft +await payload.create({ + collection: 'posts', + data: { title: 'Draft Post' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft version if exists +}) +``` + +## Globals + +Globals are single-instance documents (not collections). + +```typescript +import type { GlobalConfig } from 'payload' + +export const Header: GlobalConfig = { + slug: 'header', + label: 'Header', + admin: { + group: 'Settings', + }, + fields: [ + { + name: 'logo', + type: 'upload', + relationTo: 'media', + required: true, + }, + { + name: 'nav', + type: 'array', + maxRows: 8, + fields: [ + { + name: 'link', + type: 'relationship', + relationTo: 'pages', + }, + { + name: 'label', + type: 'text', + }, + ], + }, + ], +} +``` diff --git a/templates/blank/.cursor/rules/components.md b/templates/blank/.cursor/rules/components.md new file mode 100644 index 00000000000..8610b8d7b33 --- /dev/null +++ b/templates/blank/.cursor/rules/components.md @@ -0,0 +1,794 @@ +# Custom Components in Payload CMS + +Custom Components allow you to fully customize the Admin Panel by swapping in your own React components. You can replace nearly every part of the interface or add entirely new functionality. + +## Component Types + +There are four main types of Custom Components: + +1. **Root Components** - Affect the Admin Panel globally (logo, nav, header) +2. **Collection Components** - Specific to collection views +3. **Global Components** - Specific to global document views +4. **Field Components** - Custom field UI and cells + +## Defining Custom Components + +### Component Paths + +Components are defined using file paths (not direct imports) to keep the config lightweight and Node.js compatible. + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + logout: { + Button: '/src/components/Logout#MyComponent', // Named export + }, + Nav: '/src/components/Nav', // Default export + }, + }, +}) +``` + +**Component Path Rules:** + +1. Paths are relative to project root (or `config.admin.importMap.baseDir`) +2. For **named exports**: append `#ExportName` or use `exportName` property +3. For **default exports**: no suffix needed +4. File extensions can be omitted + +### Component Config Object + +Instead of a string path, you can pass a config object: + +```typescript +{ + logout: { + Button: { + path: '/src/components/Logout', + exportName: 'MyComponent', + clientProps: { customProp: 'value' }, + serverProps: { asyncData: someData }, + }, + }, +} +``` + +**Config Properties:** + +| Property | Description | +| ------------- | ----------------------------------------------------- | +| `path` | File path to component (named exports via `#`) | +| `exportName` | Named export (alternative to `#` in path) | +| `clientProps` | Props for Client Components (must be serializable) | +| `serverProps` | Props for Server Components (can be non-serializable) | + +### Setting Base Directory + +```typescript +import path from 'path' +import { fileURLToPath } from 'node:url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), // Set base directory + }, + components: { + Nav: '/components/Nav', // Now relative to src/ + }, + }, +}) +``` + +## Server vs Client Components + +**All components are React Server Components by default.** + +### Server Components (Default) + +Can use Local API directly, perform async operations, and access full Payload instance. + +```tsx +import React from 'react' +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const page = await payload.findByID({ + collection: 'pages', + id: '123', + }) + + return

{page.title}

+} + +export default MyServerComponent +``` + +### Client Components + +Use the `'use client'` directive for interactivity, hooks, state, etc. + +```tsx +'use client' +import React, { useState } from 'react' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + + return +} +``` + +**Important:** Client Components cannot receive non-serializable props (functions, class instances, etc.). Payload automatically strips these when passing to client components. + +## Default Props + +All Custom Components receive these props by default: + +| Prop | Description | Type | +| --------- | ---------------------------------------- | --------- | +| `payload` | Payload instance (Local API access) | `Payload` | +| `i18n` | Internationalization object | `I18n` | +| `locale` | Current locale (if localization enabled) | `string` | + +**Server Component Example:** + +```tsx +async function MyComponent({ payload, i18n, locale }) { + const data = await payload.find({ + collection: 'posts', + locale, + }) + + return
{data.docs.length} posts
+} +``` + +**Client Component Example:** + +```tsx +'use client' +import { usePayload, useLocale, useTranslation } from '@payloadcms/ui' + +export function MyComponent() { + // Access via hooks in client components + const { getLocal, getByID } = usePayload() + const locale = useLocale() + const { t, i18n } = useTranslation() + + return
{t('myKey')}
+} +``` + +## Custom Props + +Pass additional props using `clientProps` or `serverProps`: + +```typescript +{ + logout: { + Button: { + path: '/components/Logout', + clientProps: { + buttonText: 'Sign Out', + onLogout: () => console.log('Logged out'), + }, + }, + }, +} +``` + +Receive in component: + +```tsx +'use client' +export function Logout({ buttonText, onLogout }) { + return +} +``` + +## Root Components + +Root Components affect the entire Admin Panel. + +### Available Root Components + +| Component | Description | Config Path | +| ----------------- | -------------------------------- | ---------------------------------- | +| `Nav` | Entire navigation sidebar | `admin.components.Nav` | +| `graphics.Icon` | Small icon (used in nav) | `admin.components.graphics.Icon` | +| `graphics.Logo` | Full logo (used on login) | `admin.components.graphics.Logo` | +| `logout.Button` | Logout button | `admin.components.logout.Button` | +| `actions` | Header actions (array) | `admin.components.actions` | +| `header` | Above header (array) | `admin.components.header` | +| `beforeDashboard` | Before dashboard content (array) | `admin.components.beforeDashboard` | +| `afterDashboard` | After dashboard content (array) | `admin.components.afterDashboard` | +| `beforeLogin` | Before login form (array) | `admin.components.beforeLogin` | +| `afterLogin` | After login form (array) | `admin.components.afterLogin` | +| `beforeNavLinks` | Before nav links (array) | `admin.components.beforeNavLinks` | +| `afterNavLinks` | After nav links (array) | `admin.components.afterNavLinks` | +| `settingsMenu` | Settings menu items (array) | `admin.components.settingsMenu` | +| `providers` | Custom React Context providers | `admin.components.providers` | +| `views` | Custom views (dashboard, etc.) | `admin.components.views` | + +### Example: Custom Logo + +```typescript +export default buildConfig({ + admin: { + components: { + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + }, + }, +}) +``` + +```tsx +// components/Logo.tsx +export default function Logo() { + return My Brand +} +``` + +### Example: Header Actions + +```typescript +export default buildConfig({ + admin: { + components: { + actions: ['/components/ClearCacheButton', '/components/PreviewButton'], + }, + }, +}) +``` + +```tsx +// components/ClearCacheButton.tsx +'use client' +export default function ClearCacheButton() { + return ( + + ) +} +``` + +## Collection Components + +Collection Components are specific to a collection's views. + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view components + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/CustomSaveDraft', + PublishButton: '/components/CustomPublish', + }, + + // List view components + list: { + Header: '/components/PostsListHeader', + beforeList: ['/components/ListFilters'], + afterList: ['/components/ListFooter'], + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Global Components + +Similar to Collection Components but for Global documents. + +```typescript +import type { GlobalConfig } from 'payload' + +export const Settings: GlobalConfig = { + slug: 'settings', + admin: { + components: { + edit: { + PreviewButton: '/components/SettingsPreview', + SaveButton: '/components/SettingsSave', + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Field Components + +Customize how fields render in Edit and List views. + +### Field Component (Edit View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Field: '/components/StatusField', + }, + }, +} +``` + +```tsx +// components/StatusField.tsx +'use client' +import { useField } from '@payloadcms/ui' +import type { SelectFieldClientComponent } from 'payload' + +export const StatusField: SelectFieldClientComponent = ({ path, field }) => { + const { value, setValue } = useField({ path }) + + return ( +
+ + +
+ ) +} +``` + +### Cell Component (List View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Cell: '/components/StatusCell', + }, + }, +} +``` + +```tsx +// components/StatusCell.tsx +import type { SelectFieldCellComponent } from 'payload' + +export const StatusCell: SelectFieldCellComponent = ({ data, cellData }) => { + const isPublished = cellData === 'published' + + return ( + + {cellData} + + ) +} +``` + +### UI Field (Presentational Only) + +Special field type for adding custom UI without affecting data: + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +```tsx +// components/RefundButton.tsx +'use client' +import { useDocumentInfo } from '@payloadcms/ui' + +export default function RefundButton() { + const { id } = useDocumentInfo() + + return ( + + ) +} +``` + +## Using Hooks + +Payload provides many React hooks for Client Components: + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Current document info (id, slug, etc.) + useField, // Field value and setValue + useForm, // Form state and dispatch + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +**Important:** These hooks only work in Client Components within the Admin Panel context. + +## Accessing Payload Config + +**In Server Components:** + +```tsx +async function MyServerComponent({ payload }) { + const { config } = payload + return
{config.serverURL}
+} +``` + +**In Client Components:** + +```tsx +'use client' +import { useConfig } from '@payloadcms/ui' + +export function MyClientComponent() { + const { config } = useConfig() // Client-safe config + return
{config.serverURL}
+} +``` + +**Important:** Client Components receive a serializable version of the config (functions, validation, etc. are stripped). + +## Field Config Access + +**Server Component:** + +```tsx +import type { TextFieldServerComponent } from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = ({ field }) => { + return
Field name: {field.name}
+} +``` + +**Client Component:** + +```tsx +'use client' +import type { TextFieldClientComponent } from 'payload' + +export const MyFieldComponent: TextFieldClientComponent = ({ clientField }) => { + // clientField has non-serializable props removed + return
Field name: {clientField.name}
+} +``` + +## Translations (i18n) + +**Server Component:** + +```tsx +import { getTranslation } from '@payloadcms/translations' + +async function MyServerComponent({ i18n }) { + const translatedTitle = getTranslation(myTranslation, i18n) + return

{translatedTitle}

+} +``` + +**Client Component:** + +```tsx +'use client' +import { useTranslation } from '@payloadcms/ui' + +export function MyClientComponent() { + const { t, i18n } = useTranslation() + + return ( +
+

{t('namespace:key', { variable: 'value' })}

+

Language: {i18n.language}

+
+ ) +} +``` + +## Styling Components + +### Using CSS Variables + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Custom Component
+} +``` + +```scss +// styles.scss +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} +``` + +### Importing Payload SCSS + +```scss +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +## Common Patterns + +### Conditional Field Visibility + +```tsx +'use client' +import { useFormFields } from '@payloadcms/ui' +import type { TextFieldClientComponent } from 'payload' + +export const ConditionalField: TextFieldClientComponent = ({ path }) => { + const showField = useFormFields(([fields]) => fields.enableFeature?.value) + + if (!showField) return null + + return +} +``` + +### Loading Data from API + +```tsx +'use client' +import { useState, useEffect } from 'react' + +export function DataLoader() { + const [data, setData] = useState(null) + + useEffect(() => { + fetch('/api/custom-data') + .then((res) => res.json()) + .then(setData) + }, []) + + return
{JSON.stringify(data)}
+} +``` + +### Using Local API in Server Components + +```tsx +import type { Payload } from 'payload' + +async function RelatedPosts({ payload, id }: { payload: Payload; id: string }) { + const post = await payload.findByID({ + collection: 'posts', + id, + depth: 0, + }) + + const related = await payload.find({ + collection: 'posts', + where: { + category: { equals: post.category }, + id: { not_equals: id }, + }, + limit: 5, + }) + + return ( +
+

Related Posts

+
    + {related.docs.map((doc) => ( +
  • {doc.title}
  • + ))} +
+
+ ) +} + +export default RelatedPosts +``` + +## Performance Best Practices + +### 1. Minimize Client Bundle Size + +```tsx +// ❌ BAD: Imports entire package +'use client' +import { Button } from '@payloadcms/ui' + +// ✅ GOOD: Tree-shakeable import for frontend +import { Button } from '@payloadcms/ui/elements/Button' +``` + +**Rule:** In Admin Panel UI, import from `@payloadcms/ui`. In frontend code, use specific paths. + +### 2. Optimize Re-renders + +```tsx +// ❌ BAD: Re-renders on every form change +'use client' +import { useForm } from '@payloadcms/ui' + +export function MyComponent() { + const { fields } = useForm() + // Re-renders on ANY field change +} + +// ✅ GOOD: Only re-renders when specific field changes +;('use client') +import { useFormFields } from '@payloadcms/ui' + +export function MyComponent({ path }) { + const value = useFormFields(([fields]) => fields[path]) + // Only re-renders when this field changes +} +``` + +### 3. Use Server Components When Possible + +```tsx +// ✅ GOOD: No JavaScript sent to client +async function PostCount({ payload }) { + const { totalDocs } = await payload.find({ + collection: 'posts', + limit: 0, + }) + + return

{totalDocs} posts

+} + +// Only use client components when you need: +// - State (useState, useReducer) +// - Effects (useEffect) +// - Event handlers (onClick, onChange) +// - Browser APIs (localStorage, window) +``` + +### 4. React Best Practices + +- Use React.memo() for expensive components +- Implement proper key props in lists +- Avoid inline function definitions in renders +- Use Suspense boundaries for async operations + +## Import Map + +Payload generates an import map at `app/(payload)/admin/importMap.js` that resolves all component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Override location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Type Safety + +Use Payload's TypeScript types for components: + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, +} from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = (props) => { + // Fully typed props +} +``` + +## Troubleshooting + +### "useConfig is undefined" or similar hook errors + +**Cause:** Dependency version mismatch between Payload packages. + +**Solution:** Pin all `@payloadcms/*` packages to the exact same version: + +```json +{ + "dependencies": { + "payload": "3.0.0", + "@payloadcms/ui": "3.0.0", + "@payloadcms/richtext-lexical": "3.0.0" + } +} +``` + +### Component not loading + +1. Check file path is correct (relative to baseDir) +2. Verify named export syntax: `/path/to/file#ExportName` +3. Run `payload generate:importmap` to regenerate +4. Check for TypeScript errors in component file + +## Resources + +- [Custom Components Docs](https://payloadcms.com/docs/custom-components/overview) +- [Root Components](https://payloadcms.com/docs/custom-components/root-components) +- [Custom Views](https://payloadcms.com/docs/custom-components/custom-views) +- [React Hooks](https://payloadcms.com/docs/admin/react-hooks) +- [Custom CSS](https://payloadcms.com/docs/admin/customizing-css) diff --git a/templates/blank/.cursor/rules/endpoints.md b/templates/blank/.cursor/rules/endpoints.md new file mode 100644 index 00000000000..8a2481dbe5d --- /dev/null +++ b/templates/blank/.cursor/rules/endpoints.md @@ -0,0 +1,236 @@ +--- +title: Custom Endpoints +description: Custom REST API endpoints with authentication and helpers +tags: [payload, endpoints, api, routes, webhooks] +--- + +# Payload Custom Endpoints + +## Basic Endpoint Pattern + +Custom endpoints are **not authenticated by default**. Always check `req.user`. + +```typescript +import { APIError } from 'payload' +import type { Endpoint } from 'payload' + +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} +``` + +## Route Parameters + +```typescript +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Request Body Handling + +```typescript +// Manual JSON parsing +export const createEndpoint: Endpoint = { + path: '/create', + method: 'post', + handler: async (req) => { + const data = await req.json() + + const result = await req.payload.create({ + collection: 'posts', + data, + }) + + return Response.json(result) + }, +} + +// Using helper (handles JSON + files) +import { addDataAndFileToRequest } from 'payload' + +export const uploadEndpoint: Endpoint = { + path: '/upload', + method: 'post', + handler: async (req) => { + await addDataAndFileToRequest(req) + + // req.data contains parsed body + // req.file contains uploaded file (if multipart) + + const result = await req.payload.create({ + collection: 'media', + data: req.data, + file: req.file, + }) + + return Response.json(result) + }, +} +``` + +## Query Parameters + +```typescript +export const searchEndpoint: Endpoint = { + path: '/search', + method: 'get', + handler: async (req) => { + const url = new URL(req.url) + const query = url.searchParams.get('q') + const limit = parseInt(url.searchParams.get('limit') || '10') + + const results = await req.payload.find({ + collection: 'posts', + where: { + title: { + contains: query, + }, + }, + limit, + }) + + return Response.json(results) + }, +} +``` + +## CORS Headers + +```typescript +import { headersWithCors } from 'payload' + +export const corsEndpoint: Endpoint = { + path: '/public-data', + method: 'get', + handler: async (req) => { + const data = await fetchPublicData() + + return Response.json(data, { + headers: headersWithCors({ + headers: new Headers(), + req, + }), + }) + }, +} +``` + +## Error Handling + +```typescript +import { APIError } from 'payload' + +export const validateEndpoint: Endpoint = { + path: '/validate', + method: 'post', + handler: async (req) => { + const data = await req.json() + + if (!data.email) { + throw new APIError('Email is required', 400) + } + + return Response.json({ valid: true }) + }, +} +``` + +## Endpoint Placement + +### Collection Endpoints + +Mounted at `/api/{collection-slug}/{path}`. + +```typescript +export const Orders: CollectionConfig = { + slug: 'orders', + endpoints: [ + { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + // Available at: /api/orders/:id/tracking + const orderId = req.routeParams.id + return Response.json({ orderId }) + }, + }, + ], +} +``` + +### Global Endpoints + +Mounted at `/api/globals/{global-slug}/{path}`. + +```typescript +export const Settings: GlobalConfig = { + slug: 'settings', + endpoints: [ + { + path: '/clear-cache', + method: 'post', + handler: async (req) => { + // Available at: /api/globals/settings/clear-cache + await clearCache() + return Response.json({ message: 'Cache cleared' }) + }, + }, + ], +} +``` + +### Root Endpoints + +Mounted at `/api/{path}`. + +```typescript +export default buildConfig({ + endpoints: [ + { + path: '/hello', + method: 'get', + handler: () => { + // Available at: /api/hello + return Response.json({ message: 'Hello!' }) + }, + }, + ], +}) +``` + +## Best Practices + +1. **Always check authentication** - Custom endpoints are not authenticated by default +2. **Use `req.payload` for operations** - Ensures access control and hooks execute +3. **Use helpers for common tasks** - `addDataAndFileToRequest`, `headersWithCors` +4. **Throw `APIError` for errors** - Provides consistent error responses +5. **Return Web API `Response`** - Use `Response.json()` for consistent responses +6. **Validate input** - Check required fields, validate types +7. **Log errors** - Use `req.payload.logger` for debugging diff --git a/templates/blank/.cursor/rules/field-type-guards.md b/templates/blank/.cursor/rules/field-type-guards.md new file mode 100644 index 00000000000..3514ad44993 --- /dev/null +++ b/templates/blank/.cursor/rules/field-type-guards.md @@ -0,0 +1,230 @@ +--- +title: Field Type Guards +description: Runtime field type checking and safe type narrowing +tags: [payload, typescript, type-guards, fields] +--- + +# Payload Field Type Guards + +Type guards for runtime field type checking and safe type narrowing. + +## Most Common Guards + +### fieldAffectsData + +**Most commonly used guard.** Checks if field stores data (has name and is not UI-only). + +```typescript +import { fieldAffectsData } from 'payload' + +function generateSchema(fields: Field[]) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + // Safe to access field.name + schema[field.name] = getFieldType(field) + } + }) +} + +// Filter data fields +const dataFields = fields.filter(fieldAffectsData) +``` + +### fieldHasSubFields + +Checks if field contains nested fields (group, array, row, or collapsible). + +```typescript +import { fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[]): void { + fields.forEach((field) => { + if (fieldHasSubFields(field)) { + // Safe to access field.fields + traverseFields(field.fields) + } + }) +} +``` + +### fieldIsArrayType + +Checks if field type is `'array'`. + +```typescript +import { fieldIsArrayType } from 'payload' + +if (fieldIsArrayType(field)) { + // field.type === 'array' + console.log(`Min rows: ${field.minRows}`) + console.log(`Max rows: ${field.maxRows}`) +} +``` + +## Capability Guards + +### fieldSupportsMany + +Checks if field can have multiple values (select, relationship, or upload with `hasMany`). + +```typescript +import { fieldSupportsMany } from 'payload' + +if (fieldSupportsMany(field)) { + // field.type is 'select' | 'relationship' | 'upload' + if (field.hasMany) { + console.log('Field accepts multiple values') + } +} +``` + +### fieldHasMaxDepth + +Checks if field is relationship/upload/join with numeric `maxDepth` property. + +```typescript +import { fieldHasMaxDepth } from 'payload' + +if (fieldHasMaxDepth(field)) { + // field.type is 'upload' | 'relationship' | 'join' + // AND field.maxDepth is number + const remainingDepth = field.maxDepth - currentDepth +} +``` + +### fieldIsVirtual + +Checks if field is virtual (computed or virtual relationship). + +```typescript +import { fieldIsVirtual } from 'payload' + +if (fieldIsVirtual(field)) { + // field.virtual is truthy + if (typeof field.virtual === 'string') { + console.log(`Virtual path: ${field.virtual}`) + } +} +``` + +## Type Checking Guards + +### fieldIsBlockType + +```typescript +import { fieldIsBlockType } from 'payload' + +if (fieldIsBlockType(field)) { + // field.type === 'blocks' + field.blocks.forEach((block) => { + console.log(`Block: ${block.slug}`) + }) +} +``` + +### fieldIsGroupType + +```typescript +import { fieldIsGroupType } from 'payload' + +if (fieldIsGroupType(field)) { + // field.type === 'group' + console.log(`Interface: ${field.interfaceName}`) +} +``` + +### fieldIsPresentationalOnly + +```typescript +import { fieldIsPresentationalOnly } from 'payload' + +if (fieldIsPresentationalOnly(field)) { + // field.type === 'ui' + // Skip in data operations, GraphQL schema, etc. + return +} +``` + +## Common Patterns + +### Recursive Field Traversal + +```typescript +import { fieldAffectsData, fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[], callback: (field: Field) => void) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + callback(field) + } + + if (fieldHasSubFields(field)) { + traverseFields(field.fields, callback) + } + }) +} +``` + +### Filter Data-Bearing Fields + +```typescript +import { fieldAffectsData, fieldIsPresentationalOnly, fieldIsHiddenOrDisabled } from 'payload' + +const dataFields = fields.filter( + (field) => + fieldAffectsData(field) && !fieldIsPresentationalOnly(field) && !fieldIsHiddenOrDisabled(field), +) +``` + +### Container Type Switching + +```typescript +import { fieldIsArrayType, fieldIsBlockType, fieldHasSubFields } from 'payload' + +if (fieldIsArrayType(field)) { + // Handle array-specific logic +} else if (fieldIsBlockType(field)) { + // Handle blocks-specific logic +} else if (fieldHasSubFields(field)) { + // Handle group/row/collapsible +} +``` + +### Safe Property Access + +```typescript +import { fieldSupportsMany, fieldHasMaxDepth } from 'payload' + +// With guard - safe access +if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') +} + +if (fieldHasMaxDepth(field)) { + const depth = field.maxDepth // TypeScript knows this is number +} +``` + +## All Available Guards + +| Type Guard | Checks For | Use When | +| --------------------------- | --------------------------------- | ---------------------------------------- | +| `fieldAffectsData` | Field stores data (has name) | Need to access field data or name | +| `fieldHasSubFields` | Field contains nested fields | Recursively traverse fields | +| `fieldIsArrayType` | Field is array type | Distinguish arrays from other containers | +| `fieldIsBlockType` | Field is blocks type | Handle blocks-specific logic | +| `fieldIsGroupType` | Field is group type | Handle group-specific logic | +| `fieldSupportsMany` | Field can have multiple values | Check for `hasMany` support | +| `fieldHasMaxDepth` | Field supports depth control | Control relationship/upload/join depth | +| `fieldIsPresentationalOnly` | Field is UI-only | Exclude from data operations | +| `fieldIsSidebar` | Field positioned in sidebar | Separate sidebar rendering | +| `fieldIsID` | Field name is 'id' | Special ID field handling | +| `fieldIsHiddenOrDisabled` | Field is hidden or disabled | Filter from UI operations | +| `fieldShouldBeLocalized` | Field needs localization | Proper locale table checks | +| `fieldIsVirtual` | Field is virtual | Skip in database transforms | +| `tabHasName` | Tab is named (stores data) | Distinguish named vs unnamed tabs | +| `groupHasName` | Group is named (stores data) | Distinguish named vs unnamed groups | +| `optionIsObject` | Option is `{label, value}` | Access option properties safely | +| `optionsAreObjects` | All options are objects | Batch option processing | +| `optionIsValue` | Option is string value | Handle string options | +| `valueIsValueWithRelation` | Value is polymorphic relationship | Handle polymorphic relationships | diff --git a/templates/blank/.cursor/rules/fields.md b/templates/blank/.cursor/rules/fields.md new file mode 100644 index 00000000000..8468e41f599 --- /dev/null +++ b/templates/blank/.cursor/rules/fields.md @@ -0,0 +1,317 @@ +--- +title: Fields +description: Field types, patterns, and configurations +tags: [payload, fields, validation, conditional] +--- + +# Payload CMS Fields + +## Common Field Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## Field Types + +### Text Field + +```typescript +{ + name: 'title', + type: 'text', + required: true, + unique: true, + minLength: 5, + maxLength: 100, + index: true, + localized: true, + defaultValue: 'Default Title', + validate: (value) => Boolean(value) || 'Required', + admin: { + placeholder: 'Enter title...', + position: 'sidebar', + condition: (data) => data.showTitle === true, + }, +} +``` + +### Rich Text (Lexical) + +```typescript +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { HeadingFeature, LinkFeature } from '@payloadcms/richtext-lexical' + +{ + name: 'content', + type: 'richText', + required: true, + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + HeadingFeature({ + enabledHeadingSizes: ['h1', 'h2', 'h3'], + }), + LinkFeature({ + enabledCollections: ['posts', 'pages'], + }), + ], + }), +} +``` + +### Relationship + +```typescript +// Single relationship +{ + name: 'author', + type: 'relationship', + relationTo: 'users', + required: true, + maxDepth: 2, +} + +// Multiple relationships (hasMany) +{ + name: 'categories', + type: 'relationship', + relationTo: 'categories', + hasMany: true, + filterOptions: { + active: { equals: true }, + }, +} + +// Polymorphic relationship +{ + name: 'relatedContent', + type: 'relationship', + relationTo: ['posts', 'pages'], + hasMany: true, +} +``` + +### Array + +```typescript +{ + name: 'slides', + type: 'array', + minRows: 2, + maxRows: 10, + labels: { + singular: 'Slide', + plural: 'Slides', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'image', + type: 'upload', + relationTo: 'media', + }, + ], + admin: { + initCollapsed: true, + }, +} +``` + +### Blocks + +```typescript +import type { Block } from 'payload' + +const HeroBlock: Block = { + slug: 'hero', + interfaceName: 'HeroBlock', + fields: [ + { + name: 'heading', + type: 'text', + required: true, + }, + { + name: 'background', + type: 'upload', + relationTo: 'media', + }, + ], +} + +const ContentBlock: Block = { + slug: 'content', + fields: [ + { + name: 'text', + type: 'richText', + }, + ], +} + +{ + name: 'layout', + type: 'blocks', + blocks: [HeroBlock, ContentBlock], +} +``` + +### Select + +```typescript +{ + name: 'status', + type: 'select', + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + ], + defaultValue: 'draft', + required: true, +} + +// Multiple select +{ + name: 'tags', + type: 'select', + hasMany: true, + options: ['tech', 'news', 'sports'], +} +``` + +### Upload + +```typescript +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + required: true, + filterOptions: { + mimeType: { contains: 'image' }, + }, +} +``` + +### Point (Geolocation) + +```typescript +{ + name: 'location', + type: 'point', + label: 'Location', + required: true, +} + +// Query by distance +const nearbyLocations = await payload.find({ + collection: 'stores', + where: { + location: { + near: [10, 20], // [longitude, latitude] + maxDistance: 5000, // in meters + minDistance: 1000, + }, + }, +}) +``` + +### Join Fields (Reverse Relationships) + +```typescript +// From Users collection - show user's orders +{ + name: 'orders', + type: 'join', + collection: 'orders', + on: 'customer', // The field in 'orders' that references this user +} +``` + +### Tabs & Groups + +```typescript +// Tabs +{ + type: 'tabs', + tabs: [ + { + label: 'Content', + fields: [ + { name: 'title', type: 'text' }, + { name: 'body', type: 'richText' }, + ], + }, + { + label: 'SEO', + fields: [ + { name: 'metaTitle', type: 'text' }, + { name: 'metaDescription', type: 'textarea' }, + ], + }, + ], +} + +// Group (named) +{ + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], +} +``` + +## Validation + +```typescript +{ + name: 'email', + type: 'email', + validate: (value, { operation, data, siblingData }) => { + if (operation === 'create' && !value) { + return 'Email is required' + } + if (value && !value.includes('@')) { + return 'Invalid email format' + } + return true + }, +} +``` diff --git a/templates/blank/.cursor/rules/hooks.md b/templates/blank/.cursor/rules/hooks.md new file mode 100644 index 00000000000..1f168f9eaeb --- /dev/null +++ b/templates/blank/.cursor/rules/hooks.md @@ -0,0 +1,175 @@ +--- +title: Hooks +description: Collection hooks, field hooks, and context patterns +tags: [payload, hooks, lifecycle, context] +--- + +# Payload CMS Hooks + +## Collection Hooks + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Field Hooks + +```typescript +import type { FieldHook } from 'payload' + +const beforeValidateHook: FieldHook = ({ value }) => { + return value.trim().toLowerCase() +} + +const afterReadHook: FieldHook = ({ value, req }) => { + // Hide email from non-admins + if (!req.user?.roles?.includes('admin')) { + return value.replace(/(.{2})(.*)(@.*)/, '$1***$3') + } + return value +} + +{ + name: 'email', + type: 'email', + hooks: { + beforeValidate: [beforeValidateHook], + afterRead: [afterReadHook], + }, +} +``` + +## Hook Context + +Share data between hooks or control hook behavior using request context: + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + beforeChange: [ + async ({ context }) => { + context.expensiveData = await fetchExpensiveData() + }, + ], + afterChange: [ + async ({ context, doc }) => { + // Reuse from previous hook + await processData(doc, context.expensiveData) + }, + ], + }, +} +``` + +## Next.js Revalidation Pattern + +```typescript +import type { CollectionAfterChangeHook } from 'payload' +import { revalidatePath } from 'next/cache' + +export const revalidatePage: CollectionAfterChangeHook = ({ + doc, + previousDoc, + req: { payload, context }, +}) => { + if (!context.disableRevalidate) { + if (doc._status === 'published') { + const path = doc.slug === 'home' ? '/' : `/${doc.slug}` + payload.logger.info(`Revalidating page at path: ${path}`) + revalidatePath(path) + } + + // Revalidate old path if unpublished + if (previousDoc?._status === 'published' && doc._status !== 'published') { + const oldPath = previousDoc.slug === 'home' ? '/' : `/${previousDoc.slug}` + revalidatePath(oldPath) + } + } + return doc +} +``` + +## Date Field Auto-Set + +```typescript +{ + name: 'publishedOn', + type: 'date', + hooks: { + beforeChange: [ + ({ siblingData, value }) => { + if (siblingData._status === 'published' && !value) { + return new Date() + } + return value + }, + ], + }, +} +``` + +## Best Practices + +- Use `beforeValidate` for data formatting +- Use `beforeChange` for business logic +- Use `afterChange` for side effects +- Use `afterRead` for computed fields +- Store expensive operations in `context` +- Pass `req` to nested operations for transaction safety +- Use context flags to prevent infinite loops diff --git a/templates/blank/.cursor/rules/payload-overview.md b/templates/blank/.cursor/rules/payload-overview.md new file mode 100644 index 00000000000..290c47822ab --- /dev/null +++ b/templates/blank/.cursor/rules/payload-overview.md @@ -0,0 +1,126 @@ +--- +title: Payload CMS Overview +description: Core principles and quick reference for Payload CMS development +tags: [payload, overview, quickstart] +--- + +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Quick Reference + +| Task | Solution | +| --------------------- | ---------------------------------- | +| Auto-generate slugs | `slugField()` | +| Restrict by user | Access control with query | +| Local API user ops | `user` + `overrideAccess: false` | +| Draft/publish | `versions: { drafts: true }` | +| Computed fields | `virtual: true` with afterRead | +| Conditional fields | `admin.condition` | +| Custom validation | `validate` function | +| Filter relationships | `filterOptions` on field | +| Select fields | `select` parameter | +| Auto-set dates | beforeChange hook | +| Prevent loops | `req.context` check | +| Cascading deletes | beforeDelete hook | +| Geospatial queries | `point` field with `near`/`within` | +| Reverse relationships | `join` field type | +| Query relationships | Nested property syntax | +| Complex queries | AND/OR logic | +| Transactions | Pass `req` to operations | +| Background jobs | Jobs queue with tasks | +| Custom routes | Collection custom endpoints | +| Cloud storage | Storage adapter plugins | +| Multi-language | `localization` + `localized: true` | + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/blank/.cursor/rules/plugin-development.md b/templates/blank/.cursor/rules/plugin-development.md new file mode 100644 index 00000000000..d92bb12fb40 --- /dev/null +++ b/templates/blank/.cursor/rules/plugin-development.md @@ -0,0 +1,323 @@ +--- +title: Plugin Development +description: Creating Payload CMS plugins with TypeScript patterns +tags: [payload, plugins, architecture, patterns] +--- + +# Payload Plugin Development + +## Plugin Architecture + +Plugins are functions that receive configuration options and return a function that transforms the Payload config: + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + enabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + // Transform config here + }) +``` + +**Key Pattern:** Double arrow function (currying) + +- First function: Accepts plugin options, returns plugin function +- Second function: Accepts Payload config, returns modified config + +## Adding Fields to Collections + +```typescript +export const seoPlugin = + (options: { collections?: string[] }): Plugin => + (config: Config): Config => { + const seoFields: Field[] = [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], + }, + ] + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...seoFields], + } + } + return collection + }), + } + } +``` + +## Adding New Collections + +```typescript +export const redirectsPlugin = + (options: { overrides?: Partial }): Plugin => + (config: Config): Config => { + const redirectsCollection: CollectionConfig = { + slug: 'redirects', + access: { read: () => true }, + fields: [ + { name: 'from', type: 'text', required: true, unique: true }, + { name: 'to', type: 'text', required: true }, + ], + ...options.overrides, + } + + return { + ...config, + collections: [...(config.collections || []), redirectsCollection], + } + } +``` + +## Adding Hooks + +```typescript +const resaveChildrenHook: CollectionAfterChangeHook = async ({ doc, req, operation }) => { + if (operation === 'update') { + const children = await req.payload.find({ + collection: 'pages', + where: { parent: { equals: doc.id } }, + }) + + for (const child of children.docs) { + await req.payload.update({ + collection: 'pages', + id: child.id, + data: child, + }) + } + } + return doc +} + +export const nestedDocsPlugin = + (options: { collections: string[] }): Plugin => + (config: Config): Config => ({ + ...config, + collections: (config.collections || []).map((collection) => { + if (options.collections.includes(collection.slug)) { + return { + ...collection, + hooks: { + ...(collection.hooks || {}), + afterChange: [resaveChildrenHook, ...(collection.hooks?.afterChange || [])], + }, + } + } + return collection + }), + }) +``` + +## Adding Root-Level Endpoints + +```typescript +export const seoPlugin = + (options: { generateTitle?: (doc: any) => string }): Plugin => + (config: Config): Config => { + const generateTitleEndpoint: Endpoint = { + path: '/plugin-seo/generate-title', + method: 'post', + handler: async (req) => { + const data = await req.json?.() + const result = options.generateTitle ? options.generateTitle(data.doc) : '' + return Response.json({ result }) + }, + } + + return { + ...config, + endpoints: [...(config.endpoints ?? []), generateTitleEndpoint], + } + } +``` + +## Field Overrides with Defaults + +```typescript +type FieldsOverride = (args: { defaultFields: Field[] }) => Field[] + +interface PluginConfig { + collections?: string[] + fields?: FieldsOverride +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const defaultFields: Field[] = [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ] + + const fields = + options.fields && typeof options.fields === 'function' + ? options.fields({ defaultFields }) + : defaultFields + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...fields], + } + } + return collection + }), + } + } +``` + +## Disable Plugin Pattern + +```typescript +interface PluginConfig { + disabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + // Always add collections/fields for database schema consistency + if (!config.collections) { + config.collections = [] + } + + config.collections.push({ + slug: 'plugin-collection', + fields: [{ name: 'title', type: 'text' }], + }) + + // If disabled, return early but keep schema changes + if (options.disabled) { + return config + } + + // Add endpoints, hooks, components only when enabled + config.endpoints = [ + ...(config.endpoints ?? []), + { + path: '/my-endpoint', + method: 'get', + handler: async () => Response.json({ message: 'Hello' }), + }, + ] + + return config + } +``` + +## Admin Components + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + if (!config.admin) config.admin = {} + if (!config.admin.components) config.admin.components = {} + if (!config.admin.components.beforeDashboard) { + config.admin.components.beforeDashboard = [] + } + + // Add client component + config.admin.components.beforeDashboard.push('my-plugin-name/client#BeforeDashboardClient') + + // Add server component (RSC) + config.admin.components.beforeDashboard.push('my-plugin-name/rsc#BeforeDashboardServer') + + return config + } +``` + +## onInit Hook + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const incomingOnInit = config.onInit + + config.onInit = async (payload) => { + // IMPORTANT: Call existing onInit first + if (incomingOnInit) await incomingOnInit(payload) + + // Plugin initialization + payload.logger.info('Plugin initialized') + + // Example: Seed data + const { totalDocs } = await payload.count({ + collection: 'plugin-collection', + where: { id: { equals: 'seeded-by-plugin' } }, + }) + + if (totalDocs === 0) { + await payload.create({ + collection: 'plugin-collection', + data: { id: 'seeded-by-plugin' }, + }) + } + } + + return config + } +``` + +## Best Practices + +### Preserve Existing Config + +```typescript +// ✅ Good +collections: [...(config.collections || []), newCollection] + +// ❌ Bad +collections: [newCollection] +``` + +### Respect User Overrides + +```typescript +const collection: CollectionConfig = { + slug: 'redirects', + fields: defaultFields, + ...options.overrides, // User overrides last +} +``` + +### Hook Composition + +```typescript +hooks: { + ...collection.hooks, + afterChange: [ + myHook, + ...(collection.hooks?.afterChange || []), + ], +} +``` + +### Type Safety + +```typescript +import type { Config, Plugin, CollectionConfig, Field } from 'payload' +``` diff --git a/templates/blank/.cursor/rules/queries.md b/templates/blank/.cursor/rules/queries.md new file mode 100644 index 00000000000..4920ec85f09 --- /dev/null +++ b/templates/blank/.cursor/rules/queries.md @@ -0,0 +1,223 @@ +--- +title: Queries +description: Local API, REST, and GraphQL query patterns +tags: [payload, queries, local-api, rest, graphql] +--- + +# Payload CMS Queries + +## Query Operators + +```typescript +// Equals +{ color: { equals: 'blue' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater/less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In/not in +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (point fields) +{ location: { near: [10, 20, 5000] } } // [lng, lat, maxDistance] +``` + +## AND/OR Logic + +```typescript +{ + or: [ + { color: { equals: 'mint' } }, + { + and: [ + { color: { equals: 'white' } }, + { featured: { equals: false } }, + ], + }, + ], +} +``` + +## Nested Properties + +```typescript +{ + 'author.role': { equals: 'editor' }, + 'meta.featured': { exists: true }, +} +``` + +## Local API + +```typescript +// Find documents +const posts = await payload.find({ + collection: 'posts', + where: { + status: { equals: 'published' }, + 'author.name': { contains: 'john' }, + }, + depth: 2, // Populate relationships + limit: 10, + page: 1, + sort: '-createdAt', + locale: 'en', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const post = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { + status: 'published', + }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) + +// Count +const count = await payload.count({ + collection: 'posts', + where: { + status: { equals: 'published' }, + }, +}) +``` + +## Access Control in Local API + +**CRITICAL**: Local API bypasses access control by default (`overrideAccess: true`). + +```typescript +// ❌ WRONG: User is passed but access control is bypassed +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + // Result: Operation runs with ADMIN privileges +}) + +// ✅ CORRECT: Respects user's access control permissions +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + overrideAccess: false, // Required to enforce access control +}) + +// Administrative operation (intentionally bypass access control) +const allPosts = await payload.find({ + collection: 'posts', + // No user parameter, overrideAccess defaults to true +}) +``` + +**When to use `overrideAccess: false`:** + +- Performing operations on behalf of a user +- Testing access control logic +- API routes that should respect user permissions + +## REST API + +```typescript +import { stringify } from 'qs-esm' + +const query = { + status: { equals: 'published' }, +} + +const queryString = stringify( + { + where: query, + depth: 2, + limit: 10, + }, + { addQueryPrefix: true }, +) + +const response = await fetch(`https://api.example.com/api/posts${queryString}`) +const data = await response.json() +``` + +### REST Endpoints + +``` +GET /api/{collection} - Find documents +GET /api/{collection}/{id} - Find by ID +POST /api/{collection} - Create +PATCH /api/{collection}/{id} - Update +DELETE /api/{collection}/{id} - Delete +GET /api/{collection}/count - Count documents + +GET /api/globals/{slug} - Get global +POST /api/globals/{slug} - Update global +``` + +## GraphQL + +```graphql +query { + Posts(where: { status: { equals: published } }, limit: 10, sort: "-createdAt") { + docs { + id + title + author { + name + } + } + totalDocs + hasNextPage + } +} + +mutation { + createPost(data: { title: "New Post", status: draft }) { + id + title + } +} +``` + +## Performance Best Practices + +- Set `maxDepth` on relationships to prevent over-fetching +- Use `select` to limit returned fields +- Index frequently queried fields +- Use `virtual` fields for computed data +- Cache expensive operations in hook `context` diff --git a/templates/blank/.cursor/rules/security-critical.mdc b/templates/blank/.cursor/rules/security-critical.mdc new file mode 100644 index 00000000000..adf5d9e225d --- /dev/null +++ b/templates/blank/.cursor/rules/security-critical.mdc @@ -0,0 +1,122 @@ +--- +title: Critical Security Patterns +description: The three most important security patterns in Payload CMS +tags: [payload, security, critical, access-control, transactions, hooks] +priority: high +--- + +# CRITICAL SECURITY PATTERNS + +These are the three most critical security patterns that MUST be followed in every Payload CMS project. + +## 1. Local API Access Control (MOST IMPORTANT) + +**By default, Local API operations bypass ALL access control**, even when passing a user. + +```typescript +// ❌ SECURITY BUG: Passes user but ignores their permissions +await payload.find({ + collection: 'posts', + user: someUser, // Access control is BYPASSED! +}) + +// ✅ SECURE: Actually enforces the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED for access control +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**When to use each:** + +- `overrideAccess: true` (default) - Server-side operations you trust (cron jobs, system tasks) +- `overrideAccess: false` - When operating on behalf of a user (API routes, webhooks) + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +## 2. Transaction Safety in Hooks + +**Nested operations in hooks without `req` break transaction atomicity.** + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ] +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ] +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +## 3. Prevent Infinite Hook Loops + +**Hooks triggering operations that trigger the same hooks create infinite loops.** + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ] +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ] +} +``` + +**Rule**: Use `req.context` flags to prevent hook loops diff --git a/templates/blank/AGENTS.md b/templates/blank/AGENTS.md new file mode 100644 index 00000000000..633b29b1f61 --- /dev/null +++ b/templates/blank/AGENTS.md @@ -0,0 +1,1141 @@ +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default +6. **Access Control**: Ensure roles exist when modifiyng collection or globals with access controls + +### Code Validation + +- To validate typescript correctness after modifying code run `tsc --noEmit` +- Generate import maps after creating or modifying components. + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Configuration + +### Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Collections + +### Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +### Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Fields + +### Common Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## CRITICAL SECURITY PATTERNS + +### 1. Local API Access Control (MOST IMPORTANT) + +```typescript +// ❌ SECURITY BUG: Access control bypassed +await payload.find({ + collection: 'posts', + user: someUser, // Ignored! Operation runs with ADMIN privileges +}) + +// ✅ SECURE: Enforces user permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +### 2. Transaction Safety in Hooks + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ], +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ], +} +``` + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +### 3. Prevent Infinite Hook Loops + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ], +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ], +} +``` + +## Access Control + +### Collection-Level Access + +```typescript +import type { Access } from 'payload' + +// Boolean return +const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Query constraint (row-level security) +const ownPostsOnly: Access = ({ req: { user } }) => { + if (!user) return false + if (user?.roles?.includes('admin')) return true + + return { + author: { equals: user.id }, + } +} + +// Async access check +const projectMemberAccess: Access = async ({ req, id }) => { + const { user, payload } = req + + if (!user) return false + if (user.roles?.includes('admin')) return true + + const project = await payload.findByID({ + collection: 'projects', + id: id as string, + depth: 0, + }) + + return project.members?.includes(user.id) +} +``` + +### Field-Level Access + +```typescript +// Field access ONLY returns boolean (no query constraints) +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +### Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Hooks + +### Common Hook Patterns + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Queries + +### Local API + +```typescript +// Find with complex query +const posts = await payload.find({ + collection: 'posts', + where: { + and: [{ status: { equals: 'published' } }, { 'author.name': { contains: 'john' } }], + }, + depth: 2, // Populate relationships + limit: 10, + sort: '-createdAt', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const newPost = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { status: 'published' }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) +``` + +### Query Operators + +```typescript +// Equals +{ status: { equals: 'published' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater than / less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In array +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (geospatial) +{ location: { near: [-122.4194, 37.7749, 10000] } } +``` + +### AND/OR Logic + +```typescript +{ + or: [ + { status: { equals: 'published' } }, + { author: { equals: user.id } }, + ], +} + +{ + and: [ + { status: { equals: 'published' } }, + { featured: { equals: true } }, + ], +} +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Components + +The Admin Panel can be extensively customized using React Components. Custom Components can be Server Components (default) or Client Components. + +### Defining Components + +Components are defined using **file paths** (not direct imports) in your config: + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + // Logo and branding + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + + // Navigation + Nav: '/components/CustomNav', + beforeNavLinks: ['/components/CustomNavItem'], + afterNavLinks: ['/components/NavFooter'], + + // Header + header: ['/components/AnnouncementBanner'], + actions: ['/components/ClearCache', '/components/Preview'], + + // Dashboard + beforeDashboard: ['/components/WelcomeMessage'], + afterDashboard: ['/components/Analytics'], + + // Auth + beforeLogin: ['/components/SSOButtons'], + logout: { Button: '/components/LogoutButton' }, + + // Settings + settingsMenu: ['/components/SettingsMenu'], + + // Views + views: { + dashboard: { Component: '/components/CustomDashboard' }, + }, + }, + }, +}) +``` + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Server vs Client Components + +**All components are Server Components by default** (can use Local API directly): + +```tsx +// Server Component (default) +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const posts = await payload.find({ collection: 'posts' }) + return
{posts.totalDocs} posts
+} + +export default MyServerComponent +``` + +**Client Components** need the `'use client'` directive: + +```tsx +'use client' +import { useState } from 'react' +import { useAuth } from '@payloadcms/ui' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + const { user } = useAuth() + + return ( + + ) +} +``` + +### Using Hooks (Client Components Only) + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Document info (id, collection, etc.) + useField, // Field value and setter + useForm, // Form state + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +### Collection/Global Components + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/SaveDraft', + PublishButton: '/components/Publish', + }, + + // List view + list: { + Header: '/components/ListHeader', + beforeList: ['/components/BulkActions'], + afterList: ['/components/ListFooter'], + }, + }, + }, +} +``` + +### Field Components + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + // Edit view field + Field: '/components/StatusField', + // List view cell + Cell: '/components/StatusCell', + // Field label + Label: '/components/StatusLabel', + // Field description + Description: '/components/StatusDescription', + // Error message + Error: '/components/StatusError', + }, + }, +} +``` + +**UI Field** (presentational only, no data): + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +### Performance Best Practices + +1. **Import correctly:** + + - Admin Panel: `import { Button } from '@payloadcms/ui'` + - Frontend: `import { Button } from '@payloadcms/ui/elements/Button'` + +2. **Optimize re-renders:** + + ```tsx + // ❌ BAD: Re-renders on every form change + const { fields } = useForm() + + // ✅ GOOD: Only re-renders when specific field changes + const value = useFormFields(([fields]) => fields[path]) + ``` + +3. **Prefer Server Components** - Only use Client Components when you need: + + - State (useState, useReducer) + - Effects (useEffect) + - Event handlers (onClick, onChange) + - Browser APIs (localStorage, window) + +4. **Minimize serialized props** - Server Components serialize props sent to client + +### Styling Components + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Content
+} +``` + +```scss +// Use Payload's CSS variables +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} + +// Import Payload's SCSS library +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +### Type Safety + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, + SelectFieldServerComponent, + // ... etc +} from 'payload' + +export const MyField: TextFieldClientComponent = (props) => { + // Fully typed props +} +``` + +### Import Map + +Payload auto-generates `app/(payload)/admin/importMap.js` to resolve component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Set custom location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Custom Endpoints + +```typescript +import type { Endpoint } from 'payload' +import { APIError } from 'payload' + +// Always check authentication +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} + +// Route parameters +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Drafts & Versions + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} + +// Create draft +await payload.create({ + collection: 'pages', + data: { title: 'Draft Page' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft if available +}) +``` + +## Field Type Guards + +```typescript +import { + fieldAffectsData, + fieldHasSubFields, + fieldIsArrayType, + fieldIsBlockType, + fieldSupportsMany, + fieldHasMaxDepth, +} from 'payload' + +function processField(field: Field) { + // Check if field stores data + if (fieldAffectsData(field)) { + console.log(field.name) // Safe to access + } + + // Check if field has nested fields + if (fieldHasSubFields(field)) { + field.fields.forEach(processField) // Safe to access + } + + // Check field type + if (fieldIsArrayType(field)) { + console.log(field.minRows, field.maxRows) + } + + // Check capabilities + if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') + } +} +``` + +## Plugins + +### Using Plugins + +```typescript +import { seoPlugin } from '@payloadcms/plugin-seo' +import { redirectsPlugin } from '@payloadcms/plugin-redirects' + +export default buildConfig({ + plugins: [ + seoPlugin({ + collections: ['posts', 'pages'], + }), + redirectsPlugin({ + collections: ['pages'], + }), + ], +}) +``` + +### Creating Plugins + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + collections?: string[] + enabled?: boolean +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...collection.fields, { name: 'pluginField', type: 'text' }], + } + } + return collection + }), + }) +``` + +## Best Practices + +### Security + +1. Always set `overrideAccess: false` when passing `user` to Local API +2. Field-level access only returns boolean (no query constraints) +3. Default to restrictive access, gradually add permissions +4. Never trust client-provided data +5. Use `saveToJWT: true` for roles to avoid database lookups + +### Performance + +1. Index frequently queried fields +2. Use `select` to limit returned fields +3. Set `maxDepth` on relationships to prevent over-fetching +4. Use query constraints over async operations in access control +5. Cache expensive operations in `req.context` + +### Data Integrity + +1. Always pass `req` to nested operations in hooks +2. Use context flags to prevent infinite hook loops +3. Enable transactions for MongoDB (requires replica set) and Postgres +4. Use `beforeValidate` for data formatting +5. Use `beforeChange` for business logic + +### Type Safety + +1. Run `generate:types` after schema changes +2. Import types from generated `payload-types.ts` +3. Type your user object: `import type { User } from '@/payload-types'` +4. Use `as const` for field options +5. Use field type guards for runtime type checking + +### Organization + +1. Keep collections in separate files +2. Extract access control to `access/` directory +3. Extract hooks to `hooks/` directory +4. Use reusable field factories for common patterns +5. Document complex access control with comments + +## Common Gotchas + +1. **Local API Default**: Access control bypassed unless `overrideAccess: false` +2. **Transaction Safety**: Missing `req` in nested operations breaks atomicity +3. **Hook Loops**: Operations in hooks can trigger the same hooks +4. **Field Access**: Cannot use query constraints, only boolean +5. **Relationship Depth**: Default depth is 2, set to 0 for IDs only +6. **Draft Status**: `_status` field auto-injected when drafts enabled +7. **Type Generation**: Types not updated until `generate:types` runs +8. **MongoDB Transactions**: Require replica set configuration +9. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +10. **Point Fields**: Not supported in SQLite + +## Additional Context Files + +For deeper exploration of specific topics, refer to the context files located in `.cursor/rules/`: + +### Available Context Files + +1. **`payload-overview.md`** - High-level architecture and core concepts + + - Payload structure and initialization + - Configuration fundamentals + - Database adapters overview + +2. **`security-critical.md`** - Critical security patterns (⚠️ IMPORTANT) + + - Local API access control + - Transaction safety in hooks + - Preventing infinite hook loops + +3. **`collections.md`** - Collection configurations + + - Basic collection patterns + - Auth collections with RBAC + - Upload collections + - Drafts and versioning + - Globals + +4. **`fields.md`** - Field types and patterns + + - All field types with examples + - Conditional fields + - Virtual fields + - Field validation + - Common field patterns + +5. **`field-type-guards.md`** - TypeScript field type utilities + + - Field type checking utilities + - Safe type narrowing + - Runtime field validation + +6. **`access-control.md`** - Permission patterns + + - Collection-level access + - Field-level access + - Row-level security + - RBAC patterns + - Multi-tenant access control + +7. **`access-control-advanced.md`** - Complex access patterns + + - Nested document access + - Cross-collection permissions + - Dynamic role hierarchies + - Performance optimization + +8. **`hooks.md`** - Lifecycle hooks + + - Collection hooks + - Field hooks + - Hook context patterns + - Common hook recipes + +9. **`queries.md`** - Database operations + + - Local API usage + - Query operators + - Complex queries with AND/OR + - Performance optimization + +10. **`endpoints.md`** - Custom API endpoints + + - REST endpoint patterns + - Authentication in endpoints + - Error handling + - Route parameters + +11. **`adapters.md`** - Database and storage adapters + + - MongoDB, PostgreSQL, SQLite patterns + - Storage adapter usage (S3, Azure, GCS, etc.) + - Custom adapter development + +12. **`plugin-development.md`** - Creating plugins + + - Plugin architecture + - Modifying configuration + - Plugin hooks + - Best practices + +13. **`components.md`** - Custom Components + + - Component types (Root, Collection, Global, Field) + - Server vs Client Components + - Component paths and definition + - Default and custom props + - Using hooks + - Performance best practices + - Styling components + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/blank/src/payload-types.ts b/templates/blank/src/payload-types.ts index ec118e0473e..7c24a0d57f3 100644 --- a/templates/blank/src/payload-types.ts +++ b/templates/blank/src/payload-types.ts @@ -86,6 +86,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: {}; globalsSelect: {}; locale: null; diff --git a/templates/ecommerce/.cursor/rules/access-control-advanced.md b/templates/ecommerce/.cursor/rules/access-control-advanced.md new file mode 100644 index 00000000000..68f52fd1287 --- /dev/null +++ b/templates/ecommerce/.cursor/rules/access-control-advanced.md @@ -0,0 +1,519 @@ +--- +title: Access Control - Advanced Patterns +description: Context-aware, time-based, subscription-based access, factory functions, templates +tags: [payload, access-control, security, advanced, performance] +priority: high +--- + +# Advanced Access Control Patterns + +Advanced access control patterns including context-aware access, time-based restrictions, factory functions, and production templates. + +## Context-Aware Access Patterns + +### Locale-Specific Access + +```typescript +import type { Access } from 'payload' + +export const localeSpecificAccess: Access = ({ req: { user, locale } }) => { + // Authenticated users can access all locales + if (user) return true + + // Public users can only access English content + if (locale === 'en') return true + + return false +} +``` + +### Device-Specific Access + +```typescript +export const mobileOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return /mobile|android|iphone/i.test(userAgent) +} + +export const desktopOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return !/mobile|android|iphone/i.test(userAgent) +} +``` + +### IP-Based Access + +```typescript +export const restrictedIpAccess = (allowedIps: string[]): Access => { + return ({ req: { headers } }) => { + const ip = headers?.get('x-forwarded-for') || headers?.get('x-real-ip') + return allowedIps.includes(ip || '') + } +} + +// Usage +const internalIps = ['192.168.1.0/24', '10.0.0.5'] + +export const InternalDocs: CollectionConfig = { + slug: 'internal-docs', + access: { + read: restrictedIpAccess(internalIps), + }, +} +``` + +## Time-Based Access Patterns + +### Today's Records Only + +```typescript +export const todayOnlyAccess: Access = ({ req: { user } }) => { + if (!user) return false + + const now = new Date() + const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000) + + return { + createdAt: { + greater_than_equal: startOfDay.toISOString(), + less_than: endOfDay.toISOString(), + }, + } +} +``` + +### Recent Records (Last N Days) + +```typescript +export const recentRecordsAccess = (days: number): Access => { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - days) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} + +// Usage: Users see only last 30 days, admins see all +export const Logs: CollectionConfig = { + slug: 'logs', + access: { + read: recentRecordsAccess(30), + }, +} +``` + +### Scheduled Content (Publish Date Range) + +```typescript +export const scheduledContentAccess: Access = ({ req: { user } }) => { + // Editors see all content + if (user?.roles?.includes('admin') || user?.roles?.includes('editor')) { + return true + } + + const now = new Date().toISOString() + + // Public sees only content within publish window + return { + and: [ + { publishDate: { less_than_equal: now } }, + { + or: [{ unpublishDate: { exists: false } }, { unpublishDate: { greater_than: now } }], + }, + ], + } +} +``` + +## Subscription-Based Access + +### Active Subscription Required + +```typescript +export const activeSubscriptionAccess: Access = async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + return subscription?.status === 'active' + } catch { + return false + } +} +``` + +### Subscription Tier-Based Access + +```typescript +export const tierBasedAccess = (requiredTier: string): Access => { + const tierHierarchy = ['free', 'basic', 'pro', 'enterprise'] + + return async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + if (subscription?.status !== 'active') return false + + const userTierIndex = tierHierarchy.indexOf(subscription.tier) + const requiredTierIndex = tierHierarchy.indexOf(requiredTier) + + return userTierIndex >= requiredTierIndex + } catch { + return false + } + } +} + +// Usage +export const EnterpriseFeatures: CollectionConfig = { + slug: 'enterprise-features', + access: { + read: tierBasedAccess('enterprise'), + }, +} +``` + +## Factory Functions + +### createRoleBasedAccess + +```typescript +export function createRoleBasedAccess(roles: string[]): Access { + return ({ req: { user } }) => { + if (!user) return false + return roles.some((role) => user.roles?.includes(role)) + } +} + +// Usage +const adminOrEditor = createRoleBasedAccess(['admin', 'editor']) +const moderatorAccess = createRoleBasedAccess(['admin', 'moderator']) +``` + +### createOrgScopedAccess + +```typescript +export function createOrgScopedAccess(allowAdmin = true): Access { + return ({ req: { user } }) => { + if (!user) return false + if (allowAdmin && user.roles?.includes('admin')) return true + + return { + organizationId: { in: user.organizationIds || [] }, + } + } +} + +// Usage +const orgScoped = createOrgScopedAccess() // Admins bypass +const strictOrgScoped = createOrgScopedAccess(false) // Admins also scoped +``` + +### createTeamBasedAccess + +```typescript +export function createTeamBasedAccess(teamField = 'teamId'): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + [teamField]: { in: user.teamIds || [] }, + } + } +} +``` + +### createTimeLimitedAccess + +```typescript +export function createTimeLimitedAccess(daysAccess: number): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - daysAccess) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} +``` + +## Configuration Templates + +### Public + Authenticated Collection + +```typescript +export const PublicAuthCollection: CollectionConfig = { + slug: 'posts', + access: { + // Only admins/editors can create + create: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Authenticated users see all, public sees only published + read: ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } + }, + + // Only admins/editors can update + update: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Only admins can delete + delete: ({ req: { user } }) => { + return user?.roles?.includes('admin') || false + }, + }, + versions: { + drafts: true, + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'content', type: 'richText', required: true }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], +} +``` + +### Self-Service Collection + +```typescript +export const SelfServiceCollection: CollectionConfig = { + slug: 'users', + auth: true, + access: { + // Admins can create users + create: ({ req: { user } }) => user?.roles?.includes('admin') || false, + + // Anyone can read user profiles + read: () => true, + + // Users can update self, admins can update anyone + update: ({ req: { user }, id }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + return user.id === id + }, + + // Only admins can delete + delete: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + fields: [ + { name: 'name', type: 'text', required: true }, + { name: 'email', type: 'email', required: true }, + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + access: { + // Only admins can read/update roles + read: ({ req: { user } }) => user?.roles?.includes('admin') || false, + update: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + }, + ], +} +``` + +## Performance Considerations + +### Avoid Async Operations in Hot Paths + +```typescript +// ❌ Slow: Multiple sequential async calls +export const slowAccess: Access = async ({ req: { user } }) => { + const org = await req.payload.findByID({ collection: 'orgs', id: user.orgId }) + const team = await req.payload.findByID({ collection: 'teams', id: user.teamId }) + const subscription = await req.payload.findByID({ collection: 'subs', id: user.subId }) + + return org.active && team.active && subscription.active +} + +// ✅ Fast: Use query constraints or cache in context +export const fastAccess: Access = ({ req: { user, context } }) => { + // Cache expensive lookups + if (!context.orgStatus) { + context.orgStatus = checkOrgStatus(user.orgId) + } + + return context.orgStatus +} +``` + +### Query Constraint Optimization + +```typescript +// ❌ Avoid: Non-indexed fields in constraints +export const slowQuery: Access = () => ({ + 'metadata.internalCode': { equals: 'ABC123' }, // Slow if not indexed +}) + +// ✅ Better: Use indexed fields +export const fastQuery: Access = () => ({ + status: { equals: 'active' }, // Indexed field + organizationId: { in: ['org1', 'org2'] }, // Indexed field +}) +``` + +### Field Access on Large Arrays + +```typescript +// ❌ Slow: Complex access on array fields +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: async ({ req }) => { + // Async call runs for EVERY array item + const result = await expensiveCheck() + return result + }, + }, + }, + ], +} + +// ✅ Fast: Simple checks or cache result +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: ({ req: { user }, context }) => { + // Cache once, reuse for all items + if (context.canReadSecret === undefined) { + context.canReadSecret = user?.roles?.includes('admin') + } + return context.canReadSecret + }, + }, + }, + ], +} +``` + +### Avoid N+1 Queries + +```typescript +// ❌ N+1 Problem: Query per access check +export const n1Access: Access = async ({ req, id }) => { + // Runs for EACH document in list + const doc = await req.payload.findByID({ collection: 'docs', id }) + return doc.isPublic +} + +// ✅ Better: Use query constraint to filter at DB level +export const efficientAccess: Access = () => { + return { isPublic: { equals: true } } +} +``` + +## Debugging Tips + +### Log Access Check Execution + +```typescript +export const debugAccess: Access = ({ req: { user }, id }) => { + console.log('Access check:', { + userId: user?.id, + userRoles: user?.roles, + docId: id, + timestamp: new Date().toISOString(), + }) + return true +} +``` + +### Verify Arguments Availability + +```typescript +export const checkArgsAccess: Access = (args) => { + console.log('Available arguments:', { + hasReq: 'req' in args, + hasUser: args.req?.user ? 'yes' : 'no', + hasId: args.id ? 'provided' : 'undefined', + hasData: args.data ? 'provided' : 'undefined', + }) + return true +} +``` + +### Test Access Without User + +```typescript +// In test/development +const testAccess = await payload.find({ + collection: 'posts', + overrideAccess: false, // Enforce access control + user: undefined, // Simulate no user +}) + +console.log('Public access result:', testAccess.docs.length) +``` + +## Best Practices + +1. **Default Deny**: Start with restrictive access, gradually add permissions +2. **Type Guards**: Use TypeScript for user type safety +3. **Validate Data**: Never trust frontend-provided IDs or data +4. **Async for Critical Checks**: Use async operations for important security decisions +5. **Consistent Logic**: Apply same rules at field and collection levels +6. **Test Edge Cases**: Test with no user, wrong user, admin user scenarios +7. **Monitor Access**: Log failed access attempts for security review +8. **Regular Audit**: Review access rules quarterly or after major changes +9. **Cache Wisely**: Use `req.context` for expensive operations +10. **Document Intent**: Add comments explaining complex access rules +11. **Avoid Secrets in Client**: Never expose sensitive logic to client-side +12. **Handle Errors Gracefully**: Access functions should return `false` on error, not throw +13. **Test Local API**: Remember to set `overrideAccess: false` when testing +14. **Consider Performance**: Measure impact of async operations +15. **Principle of Least Privilege**: Grant minimum access required + +## Performance Summary + +**Minimize Async Operations**: Use query constraints over async lookups when possible + +**Cache Expensive Checks**: Store results in `req.context` for reuse + +**Index Query Fields**: Ensure fields in query constraints are indexed + +**Avoid Complex Logic in Array Fields**: Simple boolean checks preferred + +**Use Query Constraints**: Let database filter rather than loading all records diff --git a/templates/ecommerce/.cursor/rules/access-control.md b/templates/ecommerce/.cursor/rules/access-control.md new file mode 100644 index 00000000000..7b9a0a4ba5c --- /dev/null +++ b/templates/ecommerce/.cursor/rules/access-control.md @@ -0,0 +1,225 @@ +--- +title: Access Control +description: Collection, field, and global access control patterns +tags: [payload, access-control, security, permissions, rbac] +--- + +# Payload CMS Access Control + +## Access Control Layers + +1. **Collection-Level**: Controls operations on entire documents (create, read, update, delete, admin) +2. **Field-Level**: Controls access to individual fields (create, read, update) +3. **Global-Level**: Controls access to global documents (read, update) + +## Collection Access Control + +```typescript +import type { Access } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + // Boolean: Only authenticated users can create + create: ({ req: { user } }) => Boolean(user), + + // Query constraint: Public sees published, users see all + read: ({ req: { user } }) => { + if (user) return true + return { status: { equals: 'published' } } + }, + + // User-specific: Admins or document owner + update: ({ req: { user }, id }) => { + if (user?.roles?.includes('admin')) return true + return { author: { equals: user?.id } } + }, + + // Async: Check related data + delete: async ({ req, id }) => { + const hasComments = await req.payload.count({ + collection: 'comments', + where: { post: { equals: id } }, + }) + return hasComments === 0 + }, + }, +} +``` + +## Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Row-Level Security + +```typescript +// Organization-scoped access +export const organizationScoped: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + + // Users see only their organization's data + return { + organization: { + equals: user?.organization, + }, + } +} + +// Team-based access +export const teamMemberAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + 'team.members': { + contains: user.id, + }, + } +} +``` + +## Field Access Control + +**Field access ONLY returns boolean** (no query constraints). + +```typescript +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +## RBAC Pattern + +Payload does NOT provide a roles system by default. Add a `roles` field to your auth collection: + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Multi-Tenant Access Control + +```typescript +interface User { + id: string + tenantId: string + roles?: string[] +} + +const tenantAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('super-admin')) return true + + return { + tenant: { + equals: (user as User).tenantId, + }, + } +} + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + create: tenantAccess, + read: tenantAccess, + update: tenantAccess, + delete: tenantAccess, + }, + fields: [ + { + name: 'tenant', + type: 'text', + required: true, + access: { + update: ({ req: { user } }) => user?.roles?.includes('super-admin'), + }, + hooks: { + beforeChange: [ + ({ req, operation, value }) => { + if (operation === 'create' && !value) { + return (req.user as User)?.tenantId + } + return value + }, + ], + }, + }, + ], +} +``` + +## Important Notes + +1. **Local API Default**: Access control is **skipped by default** in Local API (`overrideAccess: true`). When passing a `user` parameter, you must set `overrideAccess: false`: + +```typescript +// ❌ WRONG: Passes user but bypasses access control +await payload.find({ + collection: 'posts', + user: someUser, +}) + +// ✅ CORRECT: Respects the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // Required to enforce access control +}) +``` + +2. **Field Access Limitations**: Field-level access does NOT support query constraints - only boolean returns. + +3. **Admin Panel Visibility**: The `admin` access control determines if a collection appears in the admin panel for a user. diff --git a/templates/ecommerce/.cursor/rules/adapters.md b/templates/ecommerce/.cursor/rules/adapters.md new file mode 100644 index 00000000000..49b8b3367fc --- /dev/null +++ b/templates/ecommerce/.cursor/rules/adapters.md @@ -0,0 +1,209 @@ +--- +title: Database Adapters & Transactions +description: Database adapters, storage, email, and transaction patterns +tags: [payload, database, mongodb, postgres, sqlite, transactions] +--- + +# Payload CMS Adapters + +## Database Adapters + +### MongoDB + +```typescript +import { mongooseAdapter } from '@payloadcms/db-mongodb' + +export default buildConfig({ + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +### Postgres + +```typescript +import { postgresAdapter } from '@payloadcms/db-postgres' + +export default buildConfig({ + db: postgresAdapter({ + pool: { + connectionString: process.env.DATABASE_URI, + }, + push: false, // Don't auto-push schema changes + migrationDir: './migrations', + }), +}) +``` + +### SQLite + +```typescript +import { sqliteAdapter } from '@payloadcms/db-sqlite' + +export default buildConfig({ + db: sqliteAdapter({ + client: { + url: 'file:./payload.db', + }, + transactionOptions: {}, // Enable transactions (disabled by default) + }), +}) +``` + +## Transactions + +Payload automatically uses transactions for all-or-nothing database operations. + +### Threading req Through Operations + +**CRITICAL**: When performing nested operations in hooks, always pass `req` to maintain transaction context. + +```typescript +// ✅ CORRECT: Thread req through nested operations +const resaveChildren: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + // Find children - pass req + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + req, // Maintains transaction context + }) + + // Update each child - pass req + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + req, // Same transaction as parent operation + }) + } +} + +// ❌ WRONG: Missing req breaks transaction +const brokenHook: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + // Missing req - separate transaction or no transaction + }) + + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + // Missing req - if parent operation fails, these updates persist + }) + } +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +### Manual Transaction Control + +```typescript +const transactionID = await payload.db.beginTransaction() +try { + await payload.create({ + collection: 'orders', + data: orderData, + req: { transactionID }, + }) + await payload.update({ + collection: 'inventory', + id: itemId, + data: { stock: newStock }, + req: { transactionID }, + }) + await payload.db.commitTransaction(transactionID) +} catch (error) { + await payload.db.rollbackTransaction(transactionID) + throw error +} +``` + +## Storage Adapters + +Available storage adapters: + +- **@payloadcms/storage-s3** - AWS S3 +- **@payloadcms/storage-azure** - Azure Blob Storage +- **@payloadcms/storage-gcs** - Google Cloud Storage +- **@payloadcms/storage-r2** - Cloudflare R2 +- **@payloadcms/storage-vercel-blob** - Vercel Blob +- **@payloadcms/storage-uploadthing** - Uploadthing + +### AWS S3 + +```typescript +import { s3Storage } from '@payloadcms/storage-s3' + +export default buildConfig({ + plugins: [ + s3Storage({ + collections: { + media: true, + }, + bucket: process.env.S3_BUCKET, + config: { + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + region: process.env.S3_REGION, + }, + }), + ], +}) +``` + +## Email Adapters + +### Nodemailer (SMTP) + +```typescript +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' + +export default buildConfig({ + email: nodemailerAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + transportOptions: { + host: process.env.SMTP_HOST, + port: 587, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }, + }), +}) +``` + +### Resend + +```typescript +import { resendAdapter } from '@payloadcms/email-resend' + +export default buildConfig({ + email: resendAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + apiKey: process.env.RESEND_API_KEY, + }), +}) +``` + +## Important Notes + +1. **MongoDB Transactions**: Require replica set configuration +2. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +3. **Pass req**: Always pass `req` to nested operations in hooks for transaction safety +4. **Point Fields**: Not supported in SQLite diff --git a/templates/ecommerce/.cursor/rules/collections.md b/templates/ecommerce/.cursor/rules/collections.md new file mode 100644 index 00000000000..af625108e60 --- /dev/null +++ b/templates/ecommerce/.cursor/rules/collections.md @@ -0,0 +1,171 @@ +--- +title: Collections +description: Collection configurations and patterns +tags: [payload, collections, auth, upload, drafts] +--- + +# Payload CMS Collections + +## Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +## Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Upload Collection + +```typescript +export const Media: CollectionConfig = { + slug: 'media', + upload: { + staticDir: 'media', + mimeTypes: ['image/*'], + imageSizes: [ + { + name: 'thumbnail', + width: 400, + height: 300, + position: 'centre', + }, + { + name: 'card', + width: 768, + height: 1024, + }, + ], + adminThumbnail: 'thumbnail', + focalPoint: true, + crop: true, + }, + access: { + read: () => true, + }, + fields: [ + { + name: 'alt', + type: 'text', + required: true, + }, + ], +} +``` + +## Versioning & Drafts + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} +``` + +### Draft API Usage + +```typescript +// Create draft +await payload.create({ + collection: 'posts', + data: { title: 'Draft Post' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft version if exists +}) +``` + +## Globals + +Globals are single-instance documents (not collections). + +```typescript +import type { GlobalConfig } from 'payload' + +export const Header: GlobalConfig = { + slug: 'header', + label: 'Header', + admin: { + group: 'Settings', + }, + fields: [ + { + name: 'logo', + type: 'upload', + relationTo: 'media', + required: true, + }, + { + name: 'nav', + type: 'array', + maxRows: 8, + fields: [ + { + name: 'link', + type: 'relationship', + relationTo: 'pages', + }, + { + name: 'label', + type: 'text', + }, + ], + }, + ], +} +``` diff --git a/templates/ecommerce/.cursor/rules/components.md b/templates/ecommerce/.cursor/rules/components.md new file mode 100644 index 00000000000..8610b8d7b33 --- /dev/null +++ b/templates/ecommerce/.cursor/rules/components.md @@ -0,0 +1,794 @@ +# Custom Components in Payload CMS + +Custom Components allow you to fully customize the Admin Panel by swapping in your own React components. You can replace nearly every part of the interface or add entirely new functionality. + +## Component Types + +There are four main types of Custom Components: + +1. **Root Components** - Affect the Admin Panel globally (logo, nav, header) +2. **Collection Components** - Specific to collection views +3. **Global Components** - Specific to global document views +4. **Field Components** - Custom field UI and cells + +## Defining Custom Components + +### Component Paths + +Components are defined using file paths (not direct imports) to keep the config lightweight and Node.js compatible. + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + logout: { + Button: '/src/components/Logout#MyComponent', // Named export + }, + Nav: '/src/components/Nav', // Default export + }, + }, +}) +``` + +**Component Path Rules:** + +1. Paths are relative to project root (or `config.admin.importMap.baseDir`) +2. For **named exports**: append `#ExportName` or use `exportName` property +3. For **default exports**: no suffix needed +4. File extensions can be omitted + +### Component Config Object + +Instead of a string path, you can pass a config object: + +```typescript +{ + logout: { + Button: { + path: '/src/components/Logout', + exportName: 'MyComponent', + clientProps: { customProp: 'value' }, + serverProps: { asyncData: someData }, + }, + }, +} +``` + +**Config Properties:** + +| Property | Description | +| ------------- | ----------------------------------------------------- | +| `path` | File path to component (named exports via `#`) | +| `exportName` | Named export (alternative to `#` in path) | +| `clientProps` | Props for Client Components (must be serializable) | +| `serverProps` | Props for Server Components (can be non-serializable) | + +### Setting Base Directory + +```typescript +import path from 'path' +import { fileURLToPath } from 'node:url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), // Set base directory + }, + components: { + Nav: '/components/Nav', // Now relative to src/ + }, + }, +}) +``` + +## Server vs Client Components + +**All components are React Server Components by default.** + +### Server Components (Default) + +Can use Local API directly, perform async operations, and access full Payload instance. + +```tsx +import React from 'react' +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const page = await payload.findByID({ + collection: 'pages', + id: '123', + }) + + return

{page.title}

+} + +export default MyServerComponent +``` + +### Client Components + +Use the `'use client'` directive for interactivity, hooks, state, etc. + +```tsx +'use client' +import React, { useState } from 'react' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + + return +} +``` + +**Important:** Client Components cannot receive non-serializable props (functions, class instances, etc.). Payload automatically strips these when passing to client components. + +## Default Props + +All Custom Components receive these props by default: + +| Prop | Description | Type | +| --------- | ---------------------------------------- | --------- | +| `payload` | Payload instance (Local API access) | `Payload` | +| `i18n` | Internationalization object | `I18n` | +| `locale` | Current locale (if localization enabled) | `string` | + +**Server Component Example:** + +```tsx +async function MyComponent({ payload, i18n, locale }) { + const data = await payload.find({ + collection: 'posts', + locale, + }) + + return
{data.docs.length} posts
+} +``` + +**Client Component Example:** + +```tsx +'use client' +import { usePayload, useLocale, useTranslation } from '@payloadcms/ui' + +export function MyComponent() { + // Access via hooks in client components + const { getLocal, getByID } = usePayload() + const locale = useLocale() + const { t, i18n } = useTranslation() + + return
{t('myKey')}
+} +``` + +## Custom Props + +Pass additional props using `clientProps` or `serverProps`: + +```typescript +{ + logout: { + Button: { + path: '/components/Logout', + clientProps: { + buttonText: 'Sign Out', + onLogout: () => console.log('Logged out'), + }, + }, + }, +} +``` + +Receive in component: + +```tsx +'use client' +export function Logout({ buttonText, onLogout }) { + return +} +``` + +## Root Components + +Root Components affect the entire Admin Panel. + +### Available Root Components + +| Component | Description | Config Path | +| ----------------- | -------------------------------- | ---------------------------------- | +| `Nav` | Entire navigation sidebar | `admin.components.Nav` | +| `graphics.Icon` | Small icon (used in nav) | `admin.components.graphics.Icon` | +| `graphics.Logo` | Full logo (used on login) | `admin.components.graphics.Logo` | +| `logout.Button` | Logout button | `admin.components.logout.Button` | +| `actions` | Header actions (array) | `admin.components.actions` | +| `header` | Above header (array) | `admin.components.header` | +| `beforeDashboard` | Before dashboard content (array) | `admin.components.beforeDashboard` | +| `afterDashboard` | After dashboard content (array) | `admin.components.afterDashboard` | +| `beforeLogin` | Before login form (array) | `admin.components.beforeLogin` | +| `afterLogin` | After login form (array) | `admin.components.afterLogin` | +| `beforeNavLinks` | Before nav links (array) | `admin.components.beforeNavLinks` | +| `afterNavLinks` | After nav links (array) | `admin.components.afterNavLinks` | +| `settingsMenu` | Settings menu items (array) | `admin.components.settingsMenu` | +| `providers` | Custom React Context providers | `admin.components.providers` | +| `views` | Custom views (dashboard, etc.) | `admin.components.views` | + +### Example: Custom Logo + +```typescript +export default buildConfig({ + admin: { + components: { + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + }, + }, +}) +``` + +```tsx +// components/Logo.tsx +export default function Logo() { + return My Brand +} +``` + +### Example: Header Actions + +```typescript +export default buildConfig({ + admin: { + components: { + actions: ['/components/ClearCacheButton', '/components/PreviewButton'], + }, + }, +}) +``` + +```tsx +// components/ClearCacheButton.tsx +'use client' +export default function ClearCacheButton() { + return ( + + ) +} +``` + +## Collection Components + +Collection Components are specific to a collection's views. + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view components + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/CustomSaveDraft', + PublishButton: '/components/CustomPublish', + }, + + // List view components + list: { + Header: '/components/PostsListHeader', + beforeList: ['/components/ListFilters'], + afterList: ['/components/ListFooter'], + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Global Components + +Similar to Collection Components but for Global documents. + +```typescript +import type { GlobalConfig } from 'payload' + +export const Settings: GlobalConfig = { + slug: 'settings', + admin: { + components: { + edit: { + PreviewButton: '/components/SettingsPreview', + SaveButton: '/components/SettingsSave', + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Field Components + +Customize how fields render in Edit and List views. + +### Field Component (Edit View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Field: '/components/StatusField', + }, + }, +} +``` + +```tsx +// components/StatusField.tsx +'use client' +import { useField } from '@payloadcms/ui' +import type { SelectFieldClientComponent } from 'payload' + +export const StatusField: SelectFieldClientComponent = ({ path, field }) => { + const { value, setValue } = useField({ path }) + + return ( +
+ + +
+ ) +} +``` + +### Cell Component (List View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Cell: '/components/StatusCell', + }, + }, +} +``` + +```tsx +// components/StatusCell.tsx +import type { SelectFieldCellComponent } from 'payload' + +export const StatusCell: SelectFieldCellComponent = ({ data, cellData }) => { + const isPublished = cellData === 'published' + + return ( + + {cellData} + + ) +} +``` + +### UI Field (Presentational Only) + +Special field type for adding custom UI without affecting data: + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +```tsx +// components/RefundButton.tsx +'use client' +import { useDocumentInfo } from '@payloadcms/ui' + +export default function RefundButton() { + const { id } = useDocumentInfo() + + return ( + + ) +} +``` + +## Using Hooks + +Payload provides many React hooks for Client Components: + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Current document info (id, slug, etc.) + useField, // Field value and setValue + useForm, // Form state and dispatch + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +**Important:** These hooks only work in Client Components within the Admin Panel context. + +## Accessing Payload Config + +**In Server Components:** + +```tsx +async function MyServerComponent({ payload }) { + const { config } = payload + return
{config.serverURL}
+} +``` + +**In Client Components:** + +```tsx +'use client' +import { useConfig } from '@payloadcms/ui' + +export function MyClientComponent() { + const { config } = useConfig() // Client-safe config + return
{config.serverURL}
+} +``` + +**Important:** Client Components receive a serializable version of the config (functions, validation, etc. are stripped). + +## Field Config Access + +**Server Component:** + +```tsx +import type { TextFieldServerComponent } from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = ({ field }) => { + return
Field name: {field.name}
+} +``` + +**Client Component:** + +```tsx +'use client' +import type { TextFieldClientComponent } from 'payload' + +export const MyFieldComponent: TextFieldClientComponent = ({ clientField }) => { + // clientField has non-serializable props removed + return
Field name: {clientField.name}
+} +``` + +## Translations (i18n) + +**Server Component:** + +```tsx +import { getTranslation } from '@payloadcms/translations' + +async function MyServerComponent({ i18n }) { + const translatedTitle = getTranslation(myTranslation, i18n) + return

{translatedTitle}

+} +``` + +**Client Component:** + +```tsx +'use client' +import { useTranslation } from '@payloadcms/ui' + +export function MyClientComponent() { + const { t, i18n } = useTranslation() + + return ( +
+

{t('namespace:key', { variable: 'value' })}

+

Language: {i18n.language}

+
+ ) +} +``` + +## Styling Components + +### Using CSS Variables + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Custom Component
+} +``` + +```scss +// styles.scss +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} +``` + +### Importing Payload SCSS + +```scss +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +## Common Patterns + +### Conditional Field Visibility + +```tsx +'use client' +import { useFormFields } from '@payloadcms/ui' +import type { TextFieldClientComponent } from 'payload' + +export const ConditionalField: TextFieldClientComponent = ({ path }) => { + const showField = useFormFields(([fields]) => fields.enableFeature?.value) + + if (!showField) return null + + return +} +``` + +### Loading Data from API + +```tsx +'use client' +import { useState, useEffect } from 'react' + +export function DataLoader() { + const [data, setData] = useState(null) + + useEffect(() => { + fetch('/api/custom-data') + .then((res) => res.json()) + .then(setData) + }, []) + + return
{JSON.stringify(data)}
+} +``` + +### Using Local API in Server Components + +```tsx +import type { Payload } from 'payload' + +async function RelatedPosts({ payload, id }: { payload: Payload; id: string }) { + const post = await payload.findByID({ + collection: 'posts', + id, + depth: 0, + }) + + const related = await payload.find({ + collection: 'posts', + where: { + category: { equals: post.category }, + id: { not_equals: id }, + }, + limit: 5, + }) + + return ( +
+

Related Posts

+
    + {related.docs.map((doc) => ( +
  • {doc.title}
  • + ))} +
+
+ ) +} + +export default RelatedPosts +``` + +## Performance Best Practices + +### 1. Minimize Client Bundle Size + +```tsx +// ❌ BAD: Imports entire package +'use client' +import { Button } from '@payloadcms/ui' + +// ✅ GOOD: Tree-shakeable import for frontend +import { Button } from '@payloadcms/ui/elements/Button' +``` + +**Rule:** In Admin Panel UI, import from `@payloadcms/ui`. In frontend code, use specific paths. + +### 2. Optimize Re-renders + +```tsx +// ❌ BAD: Re-renders on every form change +'use client' +import { useForm } from '@payloadcms/ui' + +export function MyComponent() { + const { fields } = useForm() + // Re-renders on ANY field change +} + +// ✅ GOOD: Only re-renders when specific field changes +;('use client') +import { useFormFields } from '@payloadcms/ui' + +export function MyComponent({ path }) { + const value = useFormFields(([fields]) => fields[path]) + // Only re-renders when this field changes +} +``` + +### 3. Use Server Components When Possible + +```tsx +// ✅ GOOD: No JavaScript sent to client +async function PostCount({ payload }) { + const { totalDocs } = await payload.find({ + collection: 'posts', + limit: 0, + }) + + return

{totalDocs} posts

+} + +// Only use client components when you need: +// - State (useState, useReducer) +// - Effects (useEffect) +// - Event handlers (onClick, onChange) +// - Browser APIs (localStorage, window) +``` + +### 4. React Best Practices + +- Use React.memo() for expensive components +- Implement proper key props in lists +- Avoid inline function definitions in renders +- Use Suspense boundaries for async operations + +## Import Map + +Payload generates an import map at `app/(payload)/admin/importMap.js` that resolves all component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Override location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Type Safety + +Use Payload's TypeScript types for components: + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, +} from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = (props) => { + // Fully typed props +} +``` + +## Troubleshooting + +### "useConfig is undefined" or similar hook errors + +**Cause:** Dependency version mismatch between Payload packages. + +**Solution:** Pin all `@payloadcms/*` packages to the exact same version: + +```json +{ + "dependencies": { + "payload": "3.0.0", + "@payloadcms/ui": "3.0.0", + "@payloadcms/richtext-lexical": "3.0.0" + } +} +``` + +### Component not loading + +1. Check file path is correct (relative to baseDir) +2. Verify named export syntax: `/path/to/file#ExportName` +3. Run `payload generate:importmap` to regenerate +4. Check for TypeScript errors in component file + +## Resources + +- [Custom Components Docs](https://payloadcms.com/docs/custom-components/overview) +- [Root Components](https://payloadcms.com/docs/custom-components/root-components) +- [Custom Views](https://payloadcms.com/docs/custom-components/custom-views) +- [React Hooks](https://payloadcms.com/docs/admin/react-hooks) +- [Custom CSS](https://payloadcms.com/docs/admin/customizing-css) diff --git a/templates/ecommerce/.cursor/rules/endpoints.md b/templates/ecommerce/.cursor/rules/endpoints.md new file mode 100644 index 00000000000..8a2481dbe5d --- /dev/null +++ b/templates/ecommerce/.cursor/rules/endpoints.md @@ -0,0 +1,236 @@ +--- +title: Custom Endpoints +description: Custom REST API endpoints with authentication and helpers +tags: [payload, endpoints, api, routes, webhooks] +--- + +# Payload Custom Endpoints + +## Basic Endpoint Pattern + +Custom endpoints are **not authenticated by default**. Always check `req.user`. + +```typescript +import { APIError } from 'payload' +import type { Endpoint } from 'payload' + +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} +``` + +## Route Parameters + +```typescript +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Request Body Handling + +```typescript +// Manual JSON parsing +export const createEndpoint: Endpoint = { + path: '/create', + method: 'post', + handler: async (req) => { + const data = await req.json() + + const result = await req.payload.create({ + collection: 'posts', + data, + }) + + return Response.json(result) + }, +} + +// Using helper (handles JSON + files) +import { addDataAndFileToRequest } from 'payload' + +export const uploadEndpoint: Endpoint = { + path: '/upload', + method: 'post', + handler: async (req) => { + await addDataAndFileToRequest(req) + + // req.data contains parsed body + // req.file contains uploaded file (if multipart) + + const result = await req.payload.create({ + collection: 'media', + data: req.data, + file: req.file, + }) + + return Response.json(result) + }, +} +``` + +## Query Parameters + +```typescript +export const searchEndpoint: Endpoint = { + path: '/search', + method: 'get', + handler: async (req) => { + const url = new URL(req.url) + const query = url.searchParams.get('q') + const limit = parseInt(url.searchParams.get('limit') || '10') + + const results = await req.payload.find({ + collection: 'posts', + where: { + title: { + contains: query, + }, + }, + limit, + }) + + return Response.json(results) + }, +} +``` + +## CORS Headers + +```typescript +import { headersWithCors } from 'payload' + +export const corsEndpoint: Endpoint = { + path: '/public-data', + method: 'get', + handler: async (req) => { + const data = await fetchPublicData() + + return Response.json(data, { + headers: headersWithCors({ + headers: new Headers(), + req, + }), + }) + }, +} +``` + +## Error Handling + +```typescript +import { APIError } from 'payload' + +export const validateEndpoint: Endpoint = { + path: '/validate', + method: 'post', + handler: async (req) => { + const data = await req.json() + + if (!data.email) { + throw new APIError('Email is required', 400) + } + + return Response.json({ valid: true }) + }, +} +``` + +## Endpoint Placement + +### Collection Endpoints + +Mounted at `/api/{collection-slug}/{path}`. + +```typescript +export const Orders: CollectionConfig = { + slug: 'orders', + endpoints: [ + { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + // Available at: /api/orders/:id/tracking + const orderId = req.routeParams.id + return Response.json({ orderId }) + }, + }, + ], +} +``` + +### Global Endpoints + +Mounted at `/api/globals/{global-slug}/{path}`. + +```typescript +export const Settings: GlobalConfig = { + slug: 'settings', + endpoints: [ + { + path: '/clear-cache', + method: 'post', + handler: async (req) => { + // Available at: /api/globals/settings/clear-cache + await clearCache() + return Response.json({ message: 'Cache cleared' }) + }, + }, + ], +} +``` + +### Root Endpoints + +Mounted at `/api/{path}`. + +```typescript +export default buildConfig({ + endpoints: [ + { + path: '/hello', + method: 'get', + handler: () => { + // Available at: /api/hello + return Response.json({ message: 'Hello!' }) + }, + }, + ], +}) +``` + +## Best Practices + +1. **Always check authentication** - Custom endpoints are not authenticated by default +2. **Use `req.payload` for operations** - Ensures access control and hooks execute +3. **Use helpers for common tasks** - `addDataAndFileToRequest`, `headersWithCors` +4. **Throw `APIError` for errors** - Provides consistent error responses +5. **Return Web API `Response`** - Use `Response.json()` for consistent responses +6. **Validate input** - Check required fields, validate types +7. **Log errors** - Use `req.payload.logger` for debugging diff --git a/templates/ecommerce/.cursor/rules/field-type-guards.md b/templates/ecommerce/.cursor/rules/field-type-guards.md new file mode 100644 index 00000000000..3514ad44993 --- /dev/null +++ b/templates/ecommerce/.cursor/rules/field-type-guards.md @@ -0,0 +1,230 @@ +--- +title: Field Type Guards +description: Runtime field type checking and safe type narrowing +tags: [payload, typescript, type-guards, fields] +--- + +# Payload Field Type Guards + +Type guards for runtime field type checking and safe type narrowing. + +## Most Common Guards + +### fieldAffectsData + +**Most commonly used guard.** Checks if field stores data (has name and is not UI-only). + +```typescript +import { fieldAffectsData } from 'payload' + +function generateSchema(fields: Field[]) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + // Safe to access field.name + schema[field.name] = getFieldType(field) + } + }) +} + +// Filter data fields +const dataFields = fields.filter(fieldAffectsData) +``` + +### fieldHasSubFields + +Checks if field contains nested fields (group, array, row, or collapsible). + +```typescript +import { fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[]): void { + fields.forEach((field) => { + if (fieldHasSubFields(field)) { + // Safe to access field.fields + traverseFields(field.fields) + } + }) +} +``` + +### fieldIsArrayType + +Checks if field type is `'array'`. + +```typescript +import { fieldIsArrayType } from 'payload' + +if (fieldIsArrayType(field)) { + // field.type === 'array' + console.log(`Min rows: ${field.minRows}`) + console.log(`Max rows: ${field.maxRows}`) +} +``` + +## Capability Guards + +### fieldSupportsMany + +Checks if field can have multiple values (select, relationship, or upload with `hasMany`). + +```typescript +import { fieldSupportsMany } from 'payload' + +if (fieldSupportsMany(field)) { + // field.type is 'select' | 'relationship' | 'upload' + if (field.hasMany) { + console.log('Field accepts multiple values') + } +} +``` + +### fieldHasMaxDepth + +Checks if field is relationship/upload/join with numeric `maxDepth` property. + +```typescript +import { fieldHasMaxDepth } from 'payload' + +if (fieldHasMaxDepth(field)) { + // field.type is 'upload' | 'relationship' | 'join' + // AND field.maxDepth is number + const remainingDepth = field.maxDepth - currentDepth +} +``` + +### fieldIsVirtual + +Checks if field is virtual (computed or virtual relationship). + +```typescript +import { fieldIsVirtual } from 'payload' + +if (fieldIsVirtual(field)) { + // field.virtual is truthy + if (typeof field.virtual === 'string') { + console.log(`Virtual path: ${field.virtual}`) + } +} +``` + +## Type Checking Guards + +### fieldIsBlockType + +```typescript +import { fieldIsBlockType } from 'payload' + +if (fieldIsBlockType(field)) { + // field.type === 'blocks' + field.blocks.forEach((block) => { + console.log(`Block: ${block.slug}`) + }) +} +``` + +### fieldIsGroupType + +```typescript +import { fieldIsGroupType } from 'payload' + +if (fieldIsGroupType(field)) { + // field.type === 'group' + console.log(`Interface: ${field.interfaceName}`) +} +``` + +### fieldIsPresentationalOnly + +```typescript +import { fieldIsPresentationalOnly } from 'payload' + +if (fieldIsPresentationalOnly(field)) { + // field.type === 'ui' + // Skip in data operations, GraphQL schema, etc. + return +} +``` + +## Common Patterns + +### Recursive Field Traversal + +```typescript +import { fieldAffectsData, fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[], callback: (field: Field) => void) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + callback(field) + } + + if (fieldHasSubFields(field)) { + traverseFields(field.fields, callback) + } + }) +} +``` + +### Filter Data-Bearing Fields + +```typescript +import { fieldAffectsData, fieldIsPresentationalOnly, fieldIsHiddenOrDisabled } from 'payload' + +const dataFields = fields.filter( + (field) => + fieldAffectsData(field) && !fieldIsPresentationalOnly(field) && !fieldIsHiddenOrDisabled(field), +) +``` + +### Container Type Switching + +```typescript +import { fieldIsArrayType, fieldIsBlockType, fieldHasSubFields } from 'payload' + +if (fieldIsArrayType(field)) { + // Handle array-specific logic +} else if (fieldIsBlockType(field)) { + // Handle blocks-specific logic +} else if (fieldHasSubFields(field)) { + // Handle group/row/collapsible +} +``` + +### Safe Property Access + +```typescript +import { fieldSupportsMany, fieldHasMaxDepth } from 'payload' + +// With guard - safe access +if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') +} + +if (fieldHasMaxDepth(field)) { + const depth = field.maxDepth // TypeScript knows this is number +} +``` + +## All Available Guards + +| Type Guard | Checks For | Use When | +| --------------------------- | --------------------------------- | ---------------------------------------- | +| `fieldAffectsData` | Field stores data (has name) | Need to access field data or name | +| `fieldHasSubFields` | Field contains nested fields | Recursively traverse fields | +| `fieldIsArrayType` | Field is array type | Distinguish arrays from other containers | +| `fieldIsBlockType` | Field is blocks type | Handle blocks-specific logic | +| `fieldIsGroupType` | Field is group type | Handle group-specific logic | +| `fieldSupportsMany` | Field can have multiple values | Check for `hasMany` support | +| `fieldHasMaxDepth` | Field supports depth control | Control relationship/upload/join depth | +| `fieldIsPresentationalOnly` | Field is UI-only | Exclude from data operations | +| `fieldIsSidebar` | Field positioned in sidebar | Separate sidebar rendering | +| `fieldIsID` | Field name is 'id' | Special ID field handling | +| `fieldIsHiddenOrDisabled` | Field is hidden or disabled | Filter from UI operations | +| `fieldShouldBeLocalized` | Field needs localization | Proper locale table checks | +| `fieldIsVirtual` | Field is virtual | Skip in database transforms | +| `tabHasName` | Tab is named (stores data) | Distinguish named vs unnamed tabs | +| `groupHasName` | Group is named (stores data) | Distinguish named vs unnamed groups | +| `optionIsObject` | Option is `{label, value}` | Access option properties safely | +| `optionsAreObjects` | All options are objects | Batch option processing | +| `optionIsValue` | Option is string value | Handle string options | +| `valueIsValueWithRelation` | Value is polymorphic relationship | Handle polymorphic relationships | diff --git a/templates/ecommerce/.cursor/rules/fields.md b/templates/ecommerce/.cursor/rules/fields.md new file mode 100644 index 00000000000..8468e41f599 --- /dev/null +++ b/templates/ecommerce/.cursor/rules/fields.md @@ -0,0 +1,317 @@ +--- +title: Fields +description: Field types, patterns, and configurations +tags: [payload, fields, validation, conditional] +--- + +# Payload CMS Fields + +## Common Field Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## Field Types + +### Text Field + +```typescript +{ + name: 'title', + type: 'text', + required: true, + unique: true, + minLength: 5, + maxLength: 100, + index: true, + localized: true, + defaultValue: 'Default Title', + validate: (value) => Boolean(value) || 'Required', + admin: { + placeholder: 'Enter title...', + position: 'sidebar', + condition: (data) => data.showTitle === true, + }, +} +``` + +### Rich Text (Lexical) + +```typescript +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { HeadingFeature, LinkFeature } from '@payloadcms/richtext-lexical' + +{ + name: 'content', + type: 'richText', + required: true, + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + HeadingFeature({ + enabledHeadingSizes: ['h1', 'h2', 'h3'], + }), + LinkFeature({ + enabledCollections: ['posts', 'pages'], + }), + ], + }), +} +``` + +### Relationship + +```typescript +// Single relationship +{ + name: 'author', + type: 'relationship', + relationTo: 'users', + required: true, + maxDepth: 2, +} + +// Multiple relationships (hasMany) +{ + name: 'categories', + type: 'relationship', + relationTo: 'categories', + hasMany: true, + filterOptions: { + active: { equals: true }, + }, +} + +// Polymorphic relationship +{ + name: 'relatedContent', + type: 'relationship', + relationTo: ['posts', 'pages'], + hasMany: true, +} +``` + +### Array + +```typescript +{ + name: 'slides', + type: 'array', + minRows: 2, + maxRows: 10, + labels: { + singular: 'Slide', + plural: 'Slides', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'image', + type: 'upload', + relationTo: 'media', + }, + ], + admin: { + initCollapsed: true, + }, +} +``` + +### Blocks + +```typescript +import type { Block } from 'payload' + +const HeroBlock: Block = { + slug: 'hero', + interfaceName: 'HeroBlock', + fields: [ + { + name: 'heading', + type: 'text', + required: true, + }, + { + name: 'background', + type: 'upload', + relationTo: 'media', + }, + ], +} + +const ContentBlock: Block = { + slug: 'content', + fields: [ + { + name: 'text', + type: 'richText', + }, + ], +} + +{ + name: 'layout', + type: 'blocks', + blocks: [HeroBlock, ContentBlock], +} +``` + +### Select + +```typescript +{ + name: 'status', + type: 'select', + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + ], + defaultValue: 'draft', + required: true, +} + +// Multiple select +{ + name: 'tags', + type: 'select', + hasMany: true, + options: ['tech', 'news', 'sports'], +} +``` + +### Upload + +```typescript +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + required: true, + filterOptions: { + mimeType: { contains: 'image' }, + }, +} +``` + +### Point (Geolocation) + +```typescript +{ + name: 'location', + type: 'point', + label: 'Location', + required: true, +} + +// Query by distance +const nearbyLocations = await payload.find({ + collection: 'stores', + where: { + location: { + near: [10, 20], // [longitude, latitude] + maxDistance: 5000, // in meters + minDistance: 1000, + }, + }, +}) +``` + +### Join Fields (Reverse Relationships) + +```typescript +// From Users collection - show user's orders +{ + name: 'orders', + type: 'join', + collection: 'orders', + on: 'customer', // The field in 'orders' that references this user +} +``` + +### Tabs & Groups + +```typescript +// Tabs +{ + type: 'tabs', + tabs: [ + { + label: 'Content', + fields: [ + { name: 'title', type: 'text' }, + { name: 'body', type: 'richText' }, + ], + }, + { + label: 'SEO', + fields: [ + { name: 'metaTitle', type: 'text' }, + { name: 'metaDescription', type: 'textarea' }, + ], + }, + ], +} + +// Group (named) +{ + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], +} +``` + +## Validation + +```typescript +{ + name: 'email', + type: 'email', + validate: (value, { operation, data, siblingData }) => { + if (operation === 'create' && !value) { + return 'Email is required' + } + if (value && !value.includes('@')) { + return 'Invalid email format' + } + return true + }, +} +``` diff --git a/templates/ecommerce/.cursor/rules/hooks.md b/templates/ecommerce/.cursor/rules/hooks.md new file mode 100644 index 00000000000..1f168f9eaeb --- /dev/null +++ b/templates/ecommerce/.cursor/rules/hooks.md @@ -0,0 +1,175 @@ +--- +title: Hooks +description: Collection hooks, field hooks, and context patterns +tags: [payload, hooks, lifecycle, context] +--- + +# Payload CMS Hooks + +## Collection Hooks + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Field Hooks + +```typescript +import type { FieldHook } from 'payload' + +const beforeValidateHook: FieldHook = ({ value }) => { + return value.trim().toLowerCase() +} + +const afterReadHook: FieldHook = ({ value, req }) => { + // Hide email from non-admins + if (!req.user?.roles?.includes('admin')) { + return value.replace(/(.{2})(.*)(@.*)/, '$1***$3') + } + return value +} + +{ + name: 'email', + type: 'email', + hooks: { + beforeValidate: [beforeValidateHook], + afterRead: [afterReadHook], + }, +} +``` + +## Hook Context + +Share data between hooks or control hook behavior using request context: + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + beforeChange: [ + async ({ context }) => { + context.expensiveData = await fetchExpensiveData() + }, + ], + afterChange: [ + async ({ context, doc }) => { + // Reuse from previous hook + await processData(doc, context.expensiveData) + }, + ], + }, +} +``` + +## Next.js Revalidation Pattern + +```typescript +import type { CollectionAfterChangeHook } from 'payload' +import { revalidatePath } from 'next/cache' + +export const revalidatePage: CollectionAfterChangeHook = ({ + doc, + previousDoc, + req: { payload, context }, +}) => { + if (!context.disableRevalidate) { + if (doc._status === 'published') { + const path = doc.slug === 'home' ? '/' : `/${doc.slug}` + payload.logger.info(`Revalidating page at path: ${path}`) + revalidatePath(path) + } + + // Revalidate old path if unpublished + if (previousDoc?._status === 'published' && doc._status !== 'published') { + const oldPath = previousDoc.slug === 'home' ? '/' : `/${previousDoc.slug}` + revalidatePath(oldPath) + } + } + return doc +} +``` + +## Date Field Auto-Set + +```typescript +{ + name: 'publishedOn', + type: 'date', + hooks: { + beforeChange: [ + ({ siblingData, value }) => { + if (siblingData._status === 'published' && !value) { + return new Date() + } + return value + }, + ], + }, +} +``` + +## Best Practices + +- Use `beforeValidate` for data formatting +- Use `beforeChange` for business logic +- Use `afterChange` for side effects +- Use `afterRead` for computed fields +- Store expensive operations in `context` +- Pass `req` to nested operations for transaction safety +- Use context flags to prevent infinite loops diff --git a/templates/ecommerce/.cursor/rules/payload-overview.md b/templates/ecommerce/.cursor/rules/payload-overview.md new file mode 100644 index 00000000000..290c47822ab --- /dev/null +++ b/templates/ecommerce/.cursor/rules/payload-overview.md @@ -0,0 +1,126 @@ +--- +title: Payload CMS Overview +description: Core principles and quick reference for Payload CMS development +tags: [payload, overview, quickstart] +--- + +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Quick Reference + +| Task | Solution | +| --------------------- | ---------------------------------- | +| Auto-generate slugs | `slugField()` | +| Restrict by user | Access control with query | +| Local API user ops | `user` + `overrideAccess: false` | +| Draft/publish | `versions: { drafts: true }` | +| Computed fields | `virtual: true` with afterRead | +| Conditional fields | `admin.condition` | +| Custom validation | `validate` function | +| Filter relationships | `filterOptions` on field | +| Select fields | `select` parameter | +| Auto-set dates | beforeChange hook | +| Prevent loops | `req.context` check | +| Cascading deletes | beforeDelete hook | +| Geospatial queries | `point` field with `near`/`within` | +| Reverse relationships | `join` field type | +| Query relationships | Nested property syntax | +| Complex queries | AND/OR logic | +| Transactions | Pass `req` to operations | +| Background jobs | Jobs queue with tasks | +| Custom routes | Collection custom endpoints | +| Cloud storage | Storage adapter plugins | +| Multi-language | `localization` + `localized: true` | + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/ecommerce/.cursor/rules/plugin-development.md b/templates/ecommerce/.cursor/rules/plugin-development.md new file mode 100644 index 00000000000..d92bb12fb40 --- /dev/null +++ b/templates/ecommerce/.cursor/rules/plugin-development.md @@ -0,0 +1,323 @@ +--- +title: Plugin Development +description: Creating Payload CMS plugins with TypeScript patterns +tags: [payload, plugins, architecture, patterns] +--- + +# Payload Plugin Development + +## Plugin Architecture + +Plugins are functions that receive configuration options and return a function that transforms the Payload config: + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + enabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + // Transform config here + }) +``` + +**Key Pattern:** Double arrow function (currying) + +- First function: Accepts plugin options, returns plugin function +- Second function: Accepts Payload config, returns modified config + +## Adding Fields to Collections + +```typescript +export const seoPlugin = + (options: { collections?: string[] }): Plugin => + (config: Config): Config => { + const seoFields: Field[] = [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], + }, + ] + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...seoFields], + } + } + return collection + }), + } + } +``` + +## Adding New Collections + +```typescript +export const redirectsPlugin = + (options: { overrides?: Partial }): Plugin => + (config: Config): Config => { + const redirectsCollection: CollectionConfig = { + slug: 'redirects', + access: { read: () => true }, + fields: [ + { name: 'from', type: 'text', required: true, unique: true }, + { name: 'to', type: 'text', required: true }, + ], + ...options.overrides, + } + + return { + ...config, + collections: [...(config.collections || []), redirectsCollection], + } + } +``` + +## Adding Hooks + +```typescript +const resaveChildrenHook: CollectionAfterChangeHook = async ({ doc, req, operation }) => { + if (operation === 'update') { + const children = await req.payload.find({ + collection: 'pages', + where: { parent: { equals: doc.id } }, + }) + + for (const child of children.docs) { + await req.payload.update({ + collection: 'pages', + id: child.id, + data: child, + }) + } + } + return doc +} + +export const nestedDocsPlugin = + (options: { collections: string[] }): Plugin => + (config: Config): Config => ({ + ...config, + collections: (config.collections || []).map((collection) => { + if (options.collections.includes(collection.slug)) { + return { + ...collection, + hooks: { + ...(collection.hooks || {}), + afterChange: [resaveChildrenHook, ...(collection.hooks?.afterChange || [])], + }, + } + } + return collection + }), + }) +``` + +## Adding Root-Level Endpoints + +```typescript +export const seoPlugin = + (options: { generateTitle?: (doc: any) => string }): Plugin => + (config: Config): Config => { + const generateTitleEndpoint: Endpoint = { + path: '/plugin-seo/generate-title', + method: 'post', + handler: async (req) => { + const data = await req.json?.() + const result = options.generateTitle ? options.generateTitle(data.doc) : '' + return Response.json({ result }) + }, + } + + return { + ...config, + endpoints: [...(config.endpoints ?? []), generateTitleEndpoint], + } + } +``` + +## Field Overrides with Defaults + +```typescript +type FieldsOverride = (args: { defaultFields: Field[] }) => Field[] + +interface PluginConfig { + collections?: string[] + fields?: FieldsOverride +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const defaultFields: Field[] = [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ] + + const fields = + options.fields && typeof options.fields === 'function' + ? options.fields({ defaultFields }) + : defaultFields + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...fields], + } + } + return collection + }), + } + } +``` + +## Disable Plugin Pattern + +```typescript +interface PluginConfig { + disabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + // Always add collections/fields for database schema consistency + if (!config.collections) { + config.collections = [] + } + + config.collections.push({ + slug: 'plugin-collection', + fields: [{ name: 'title', type: 'text' }], + }) + + // If disabled, return early but keep schema changes + if (options.disabled) { + return config + } + + // Add endpoints, hooks, components only when enabled + config.endpoints = [ + ...(config.endpoints ?? []), + { + path: '/my-endpoint', + method: 'get', + handler: async () => Response.json({ message: 'Hello' }), + }, + ] + + return config + } +``` + +## Admin Components + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + if (!config.admin) config.admin = {} + if (!config.admin.components) config.admin.components = {} + if (!config.admin.components.beforeDashboard) { + config.admin.components.beforeDashboard = [] + } + + // Add client component + config.admin.components.beforeDashboard.push('my-plugin-name/client#BeforeDashboardClient') + + // Add server component (RSC) + config.admin.components.beforeDashboard.push('my-plugin-name/rsc#BeforeDashboardServer') + + return config + } +``` + +## onInit Hook + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const incomingOnInit = config.onInit + + config.onInit = async (payload) => { + // IMPORTANT: Call existing onInit first + if (incomingOnInit) await incomingOnInit(payload) + + // Plugin initialization + payload.logger.info('Plugin initialized') + + // Example: Seed data + const { totalDocs } = await payload.count({ + collection: 'plugin-collection', + where: { id: { equals: 'seeded-by-plugin' } }, + }) + + if (totalDocs === 0) { + await payload.create({ + collection: 'plugin-collection', + data: { id: 'seeded-by-plugin' }, + }) + } + } + + return config + } +``` + +## Best Practices + +### Preserve Existing Config + +```typescript +// ✅ Good +collections: [...(config.collections || []), newCollection] + +// ❌ Bad +collections: [newCollection] +``` + +### Respect User Overrides + +```typescript +const collection: CollectionConfig = { + slug: 'redirects', + fields: defaultFields, + ...options.overrides, // User overrides last +} +``` + +### Hook Composition + +```typescript +hooks: { + ...collection.hooks, + afterChange: [ + myHook, + ...(collection.hooks?.afterChange || []), + ], +} +``` + +### Type Safety + +```typescript +import type { Config, Plugin, CollectionConfig, Field } from 'payload' +``` diff --git a/templates/ecommerce/.cursor/rules/queries.md b/templates/ecommerce/.cursor/rules/queries.md new file mode 100644 index 00000000000..4920ec85f09 --- /dev/null +++ b/templates/ecommerce/.cursor/rules/queries.md @@ -0,0 +1,223 @@ +--- +title: Queries +description: Local API, REST, and GraphQL query patterns +tags: [payload, queries, local-api, rest, graphql] +--- + +# Payload CMS Queries + +## Query Operators + +```typescript +// Equals +{ color: { equals: 'blue' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater/less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In/not in +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (point fields) +{ location: { near: [10, 20, 5000] } } // [lng, lat, maxDistance] +``` + +## AND/OR Logic + +```typescript +{ + or: [ + { color: { equals: 'mint' } }, + { + and: [ + { color: { equals: 'white' } }, + { featured: { equals: false } }, + ], + }, + ], +} +``` + +## Nested Properties + +```typescript +{ + 'author.role': { equals: 'editor' }, + 'meta.featured': { exists: true }, +} +``` + +## Local API + +```typescript +// Find documents +const posts = await payload.find({ + collection: 'posts', + where: { + status: { equals: 'published' }, + 'author.name': { contains: 'john' }, + }, + depth: 2, // Populate relationships + limit: 10, + page: 1, + sort: '-createdAt', + locale: 'en', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const post = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { + status: 'published', + }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) + +// Count +const count = await payload.count({ + collection: 'posts', + where: { + status: { equals: 'published' }, + }, +}) +``` + +## Access Control in Local API + +**CRITICAL**: Local API bypasses access control by default (`overrideAccess: true`). + +```typescript +// ❌ WRONG: User is passed but access control is bypassed +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + // Result: Operation runs with ADMIN privileges +}) + +// ✅ CORRECT: Respects user's access control permissions +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + overrideAccess: false, // Required to enforce access control +}) + +// Administrative operation (intentionally bypass access control) +const allPosts = await payload.find({ + collection: 'posts', + // No user parameter, overrideAccess defaults to true +}) +``` + +**When to use `overrideAccess: false`:** + +- Performing operations on behalf of a user +- Testing access control logic +- API routes that should respect user permissions + +## REST API + +```typescript +import { stringify } from 'qs-esm' + +const query = { + status: { equals: 'published' }, +} + +const queryString = stringify( + { + where: query, + depth: 2, + limit: 10, + }, + { addQueryPrefix: true }, +) + +const response = await fetch(`https://api.example.com/api/posts${queryString}`) +const data = await response.json() +``` + +### REST Endpoints + +``` +GET /api/{collection} - Find documents +GET /api/{collection}/{id} - Find by ID +POST /api/{collection} - Create +PATCH /api/{collection}/{id} - Update +DELETE /api/{collection}/{id} - Delete +GET /api/{collection}/count - Count documents + +GET /api/globals/{slug} - Get global +POST /api/globals/{slug} - Update global +``` + +## GraphQL + +```graphql +query { + Posts(where: { status: { equals: published } }, limit: 10, sort: "-createdAt") { + docs { + id + title + author { + name + } + } + totalDocs + hasNextPage + } +} + +mutation { + createPost(data: { title: "New Post", status: draft }) { + id + title + } +} +``` + +## Performance Best Practices + +- Set `maxDepth` on relationships to prevent over-fetching +- Use `select` to limit returned fields +- Index frequently queried fields +- Use `virtual` fields for computed data +- Cache expensive operations in hook `context` diff --git a/templates/ecommerce/.cursor/rules/security-critical.mdc b/templates/ecommerce/.cursor/rules/security-critical.mdc new file mode 100644 index 00000000000..adf5d9e225d --- /dev/null +++ b/templates/ecommerce/.cursor/rules/security-critical.mdc @@ -0,0 +1,122 @@ +--- +title: Critical Security Patterns +description: The three most important security patterns in Payload CMS +tags: [payload, security, critical, access-control, transactions, hooks] +priority: high +--- + +# CRITICAL SECURITY PATTERNS + +These are the three most critical security patterns that MUST be followed in every Payload CMS project. + +## 1. Local API Access Control (MOST IMPORTANT) + +**By default, Local API operations bypass ALL access control**, even when passing a user. + +```typescript +// ❌ SECURITY BUG: Passes user but ignores their permissions +await payload.find({ + collection: 'posts', + user: someUser, // Access control is BYPASSED! +}) + +// ✅ SECURE: Actually enforces the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED for access control +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**When to use each:** + +- `overrideAccess: true` (default) - Server-side operations you trust (cron jobs, system tasks) +- `overrideAccess: false` - When operating on behalf of a user (API routes, webhooks) + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +## 2. Transaction Safety in Hooks + +**Nested operations in hooks without `req` break transaction atomicity.** + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ] +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ] +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +## 3. Prevent Infinite Hook Loops + +**Hooks triggering operations that trigger the same hooks create infinite loops.** + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ] +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ] +} +``` + +**Rule**: Use `req.context` flags to prevent hook loops diff --git a/templates/ecommerce/AGENTS.md b/templates/ecommerce/AGENTS.md new file mode 100644 index 00000000000..633b29b1f61 --- /dev/null +++ b/templates/ecommerce/AGENTS.md @@ -0,0 +1,1141 @@ +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default +6. **Access Control**: Ensure roles exist when modifiyng collection or globals with access controls + +### Code Validation + +- To validate typescript correctness after modifying code run `tsc --noEmit` +- Generate import maps after creating or modifying components. + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Configuration + +### Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Collections + +### Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +### Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Fields + +### Common Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## CRITICAL SECURITY PATTERNS + +### 1. Local API Access Control (MOST IMPORTANT) + +```typescript +// ❌ SECURITY BUG: Access control bypassed +await payload.find({ + collection: 'posts', + user: someUser, // Ignored! Operation runs with ADMIN privileges +}) + +// ✅ SECURE: Enforces user permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +### 2. Transaction Safety in Hooks + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ], +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ], +} +``` + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +### 3. Prevent Infinite Hook Loops + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ], +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ], +} +``` + +## Access Control + +### Collection-Level Access + +```typescript +import type { Access } from 'payload' + +// Boolean return +const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Query constraint (row-level security) +const ownPostsOnly: Access = ({ req: { user } }) => { + if (!user) return false + if (user?.roles?.includes('admin')) return true + + return { + author: { equals: user.id }, + } +} + +// Async access check +const projectMemberAccess: Access = async ({ req, id }) => { + const { user, payload } = req + + if (!user) return false + if (user.roles?.includes('admin')) return true + + const project = await payload.findByID({ + collection: 'projects', + id: id as string, + depth: 0, + }) + + return project.members?.includes(user.id) +} +``` + +### Field-Level Access + +```typescript +// Field access ONLY returns boolean (no query constraints) +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +### Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Hooks + +### Common Hook Patterns + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Queries + +### Local API + +```typescript +// Find with complex query +const posts = await payload.find({ + collection: 'posts', + where: { + and: [{ status: { equals: 'published' } }, { 'author.name': { contains: 'john' } }], + }, + depth: 2, // Populate relationships + limit: 10, + sort: '-createdAt', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const newPost = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { status: 'published' }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) +``` + +### Query Operators + +```typescript +// Equals +{ status: { equals: 'published' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater than / less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In array +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (geospatial) +{ location: { near: [-122.4194, 37.7749, 10000] } } +``` + +### AND/OR Logic + +```typescript +{ + or: [ + { status: { equals: 'published' } }, + { author: { equals: user.id } }, + ], +} + +{ + and: [ + { status: { equals: 'published' } }, + { featured: { equals: true } }, + ], +} +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Components + +The Admin Panel can be extensively customized using React Components. Custom Components can be Server Components (default) or Client Components. + +### Defining Components + +Components are defined using **file paths** (not direct imports) in your config: + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + // Logo and branding + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + + // Navigation + Nav: '/components/CustomNav', + beforeNavLinks: ['/components/CustomNavItem'], + afterNavLinks: ['/components/NavFooter'], + + // Header + header: ['/components/AnnouncementBanner'], + actions: ['/components/ClearCache', '/components/Preview'], + + // Dashboard + beforeDashboard: ['/components/WelcomeMessage'], + afterDashboard: ['/components/Analytics'], + + // Auth + beforeLogin: ['/components/SSOButtons'], + logout: { Button: '/components/LogoutButton' }, + + // Settings + settingsMenu: ['/components/SettingsMenu'], + + // Views + views: { + dashboard: { Component: '/components/CustomDashboard' }, + }, + }, + }, +}) +``` + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Server vs Client Components + +**All components are Server Components by default** (can use Local API directly): + +```tsx +// Server Component (default) +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const posts = await payload.find({ collection: 'posts' }) + return
{posts.totalDocs} posts
+} + +export default MyServerComponent +``` + +**Client Components** need the `'use client'` directive: + +```tsx +'use client' +import { useState } from 'react' +import { useAuth } from '@payloadcms/ui' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + const { user } = useAuth() + + return ( + + ) +} +``` + +### Using Hooks (Client Components Only) + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Document info (id, collection, etc.) + useField, // Field value and setter + useForm, // Form state + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +### Collection/Global Components + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/SaveDraft', + PublishButton: '/components/Publish', + }, + + // List view + list: { + Header: '/components/ListHeader', + beforeList: ['/components/BulkActions'], + afterList: ['/components/ListFooter'], + }, + }, + }, +} +``` + +### Field Components + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + // Edit view field + Field: '/components/StatusField', + // List view cell + Cell: '/components/StatusCell', + // Field label + Label: '/components/StatusLabel', + // Field description + Description: '/components/StatusDescription', + // Error message + Error: '/components/StatusError', + }, + }, +} +``` + +**UI Field** (presentational only, no data): + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +### Performance Best Practices + +1. **Import correctly:** + + - Admin Panel: `import { Button } from '@payloadcms/ui'` + - Frontend: `import { Button } from '@payloadcms/ui/elements/Button'` + +2. **Optimize re-renders:** + + ```tsx + // ❌ BAD: Re-renders on every form change + const { fields } = useForm() + + // ✅ GOOD: Only re-renders when specific field changes + const value = useFormFields(([fields]) => fields[path]) + ``` + +3. **Prefer Server Components** - Only use Client Components when you need: + + - State (useState, useReducer) + - Effects (useEffect) + - Event handlers (onClick, onChange) + - Browser APIs (localStorage, window) + +4. **Minimize serialized props** - Server Components serialize props sent to client + +### Styling Components + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Content
+} +``` + +```scss +// Use Payload's CSS variables +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} + +// Import Payload's SCSS library +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +### Type Safety + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, + SelectFieldServerComponent, + // ... etc +} from 'payload' + +export const MyField: TextFieldClientComponent = (props) => { + // Fully typed props +} +``` + +### Import Map + +Payload auto-generates `app/(payload)/admin/importMap.js` to resolve component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Set custom location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Custom Endpoints + +```typescript +import type { Endpoint } from 'payload' +import { APIError } from 'payload' + +// Always check authentication +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} + +// Route parameters +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Drafts & Versions + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} + +// Create draft +await payload.create({ + collection: 'pages', + data: { title: 'Draft Page' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft if available +}) +``` + +## Field Type Guards + +```typescript +import { + fieldAffectsData, + fieldHasSubFields, + fieldIsArrayType, + fieldIsBlockType, + fieldSupportsMany, + fieldHasMaxDepth, +} from 'payload' + +function processField(field: Field) { + // Check if field stores data + if (fieldAffectsData(field)) { + console.log(field.name) // Safe to access + } + + // Check if field has nested fields + if (fieldHasSubFields(field)) { + field.fields.forEach(processField) // Safe to access + } + + // Check field type + if (fieldIsArrayType(field)) { + console.log(field.minRows, field.maxRows) + } + + // Check capabilities + if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') + } +} +``` + +## Plugins + +### Using Plugins + +```typescript +import { seoPlugin } from '@payloadcms/plugin-seo' +import { redirectsPlugin } from '@payloadcms/plugin-redirects' + +export default buildConfig({ + plugins: [ + seoPlugin({ + collections: ['posts', 'pages'], + }), + redirectsPlugin({ + collections: ['pages'], + }), + ], +}) +``` + +### Creating Plugins + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + collections?: string[] + enabled?: boolean +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...collection.fields, { name: 'pluginField', type: 'text' }], + } + } + return collection + }), + }) +``` + +## Best Practices + +### Security + +1. Always set `overrideAccess: false` when passing `user` to Local API +2. Field-level access only returns boolean (no query constraints) +3. Default to restrictive access, gradually add permissions +4. Never trust client-provided data +5. Use `saveToJWT: true` for roles to avoid database lookups + +### Performance + +1. Index frequently queried fields +2. Use `select` to limit returned fields +3. Set `maxDepth` on relationships to prevent over-fetching +4. Use query constraints over async operations in access control +5. Cache expensive operations in `req.context` + +### Data Integrity + +1. Always pass `req` to nested operations in hooks +2. Use context flags to prevent infinite hook loops +3. Enable transactions for MongoDB (requires replica set) and Postgres +4. Use `beforeValidate` for data formatting +5. Use `beforeChange` for business logic + +### Type Safety + +1. Run `generate:types` after schema changes +2. Import types from generated `payload-types.ts` +3. Type your user object: `import type { User } from '@/payload-types'` +4. Use `as const` for field options +5. Use field type guards for runtime type checking + +### Organization + +1. Keep collections in separate files +2. Extract access control to `access/` directory +3. Extract hooks to `hooks/` directory +4. Use reusable field factories for common patterns +5. Document complex access control with comments + +## Common Gotchas + +1. **Local API Default**: Access control bypassed unless `overrideAccess: false` +2. **Transaction Safety**: Missing `req` in nested operations breaks atomicity +3. **Hook Loops**: Operations in hooks can trigger the same hooks +4. **Field Access**: Cannot use query constraints, only boolean +5. **Relationship Depth**: Default depth is 2, set to 0 for IDs only +6. **Draft Status**: `_status` field auto-injected when drafts enabled +7. **Type Generation**: Types not updated until `generate:types` runs +8. **MongoDB Transactions**: Require replica set configuration +9. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +10. **Point Fields**: Not supported in SQLite + +## Additional Context Files + +For deeper exploration of specific topics, refer to the context files located in `.cursor/rules/`: + +### Available Context Files + +1. **`payload-overview.md`** - High-level architecture and core concepts + + - Payload structure and initialization + - Configuration fundamentals + - Database adapters overview + +2. **`security-critical.md`** - Critical security patterns (⚠️ IMPORTANT) + + - Local API access control + - Transaction safety in hooks + - Preventing infinite hook loops + +3. **`collections.md`** - Collection configurations + + - Basic collection patterns + - Auth collections with RBAC + - Upload collections + - Drafts and versioning + - Globals + +4. **`fields.md`** - Field types and patterns + + - All field types with examples + - Conditional fields + - Virtual fields + - Field validation + - Common field patterns + +5. **`field-type-guards.md`** - TypeScript field type utilities + + - Field type checking utilities + - Safe type narrowing + - Runtime field validation + +6. **`access-control.md`** - Permission patterns + + - Collection-level access + - Field-level access + - Row-level security + - RBAC patterns + - Multi-tenant access control + +7. **`access-control-advanced.md`** - Complex access patterns + + - Nested document access + - Cross-collection permissions + - Dynamic role hierarchies + - Performance optimization + +8. **`hooks.md`** - Lifecycle hooks + + - Collection hooks + - Field hooks + - Hook context patterns + - Common hook recipes + +9. **`queries.md`** - Database operations + + - Local API usage + - Query operators + - Complex queries with AND/OR + - Performance optimization + +10. **`endpoints.md`** - Custom API endpoints + + - REST endpoint patterns + - Authentication in endpoints + - Error handling + - Route parameters + +11. **`adapters.md`** - Database and storage adapters + + - MongoDB, PostgreSQL, SQLite patterns + - Storage adapter usage (S3, Azure, GCS, etc.) + - Custom adapter development + +12. **`plugin-development.md`** - Creating plugins + + - Plugin architecture + - Modifying configuration + - Plugin hooks + - Best practices + +13. **`components.md`** - Custom Components + + - Component types (Root, Collection, Global, Field) + - Server vs Client Components + - Component paths and definition + - Default and custom props + - Using hooks + - Performance best practices + - Styling components + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/ecommerce/src/app/(payload)/admin/importMap.js b/templates/ecommerce/src/app/(payload)/admin/importMap.js index d7dffcc9bc7..57d1b2a210b 100644 --- a/templates/ecommerce/src/app/(payload)/admin/importMap.js +++ b/templates/ecommerce/src/app/(payload)/admin/importMap.js @@ -26,30 +26,51 @@ import { BeforeDashboard as BeforeDashboard_1a7510af427896d367a49dbf838d2de6 } f import { BeforeLogin as BeforeLogin_8a7ab0eb7ab5c511aba12e68480bfe5e } from '@/components/BeforeLogin' export const importMap = { - "@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e, - "@payloadcms/richtext-lexical/rsc#RscEntryLexicalField": RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e, - "@payloadcms/richtext-lexical/rsc#LexicalDiffComponent": LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e, - "@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient": InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#FixedToolbarFeatureClient": FixedToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#HeadingFeatureClient": HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#UnderlineFeatureClient": UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#BoldFeatureClient": BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#ItalicFeatureClient": ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#OrderedListFeatureClient": OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#UnorderedListFeatureClient": UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#LinkFeatureClient": LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#IndentFeatureClient": IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/richtext-lexical/client#TableFeatureClient": TableFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@payloadcms/plugin-seo/client#OverviewComponent": OverviewComponent_a8a977ebc872c5d5ea7ee689724c0860, - "@payloadcms/plugin-seo/client#MetaTitleComponent": MetaTitleComponent_a8a977ebc872c5d5ea7ee689724c0860, - "@payloadcms/plugin-seo/client#MetaImageComponent": MetaImageComponent_a8a977ebc872c5d5ea7ee689724c0860, - "@payloadcms/plugin-seo/client#MetaDescriptionComponent": MetaDescriptionComponent_a8a977ebc872c5d5ea7ee689724c0860, - "@payloadcms/plugin-seo/client#PreviewComponent": PreviewComponent_a8a977ebc872c5d5ea7ee689724c0860, - "@payloadcms/ui#SlugField": SlugField_3817bf644402e67bfe6577f60ef982de, - "@payloadcms/plugin-ecommerce/rsc#VariantOptionsSelector": VariantOptionsSelector_b91672ccd6e8b071c11142ab941fedfb, - "@payloadcms/plugin-ecommerce/client#PriceCell": PriceCell_e27bf7b8cc50640dcdd584767b8eac3c, - "@payloadcms/plugin-ecommerce/rsc#PriceInput": PriceInput_b91672ccd6e8b071c11142ab941fedfb, - "@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient": HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, - "@/components/BeforeDashboard#BeforeDashboard": BeforeDashboard_1a7510af427896d367a49dbf838d2de6, - "@/components/BeforeLogin#BeforeLogin": BeforeLogin_8a7ab0eb7ab5c511aba12e68480bfe5e + '@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell': + RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e, + '@payloadcms/richtext-lexical/rsc#RscEntryLexicalField': + RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e, + '@payloadcms/richtext-lexical/rsc#LexicalDiffComponent': + LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e, + '@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient': + InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/richtext-lexical/client#FixedToolbarFeatureClient': + FixedToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/richtext-lexical/client#HeadingFeatureClient': + HeadingFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/richtext-lexical/client#UnderlineFeatureClient': + UnderlineFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/richtext-lexical/client#BoldFeatureClient': + BoldFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/richtext-lexical/client#ItalicFeatureClient': + ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/richtext-lexical/client#OrderedListFeatureClient': + OrderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/richtext-lexical/client#UnorderedListFeatureClient': + UnorderedListFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/richtext-lexical/client#LinkFeatureClient': + LinkFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/richtext-lexical/client#IndentFeatureClient': + IndentFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/richtext-lexical/client#TableFeatureClient': + TableFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@payloadcms/plugin-seo/client#OverviewComponent': + OverviewComponent_a8a977ebc872c5d5ea7ee689724c0860, + '@payloadcms/plugin-seo/client#MetaTitleComponent': + MetaTitleComponent_a8a977ebc872c5d5ea7ee689724c0860, + '@payloadcms/plugin-seo/client#MetaImageComponent': + MetaImageComponent_a8a977ebc872c5d5ea7ee689724c0860, + '@payloadcms/plugin-seo/client#MetaDescriptionComponent': + MetaDescriptionComponent_a8a977ebc872c5d5ea7ee689724c0860, + '@payloadcms/plugin-seo/client#PreviewComponent': + PreviewComponent_a8a977ebc872c5d5ea7ee689724c0860, + '@payloadcms/ui#SlugField': SlugField_3817bf644402e67bfe6577f60ef982de, + '@payloadcms/plugin-ecommerce/rsc#VariantOptionsSelector': + VariantOptionsSelector_b91672ccd6e8b071c11142ab941fedfb, + '@payloadcms/plugin-ecommerce/client#PriceCell': PriceCell_e27bf7b8cc50640dcdd584767b8eac3c, + '@payloadcms/plugin-ecommerce/rsc#PriceInput': PriceInput_b91672ccd6e8b071c11142ab941fedfb, + '@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient': + HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, + '@/components/BeforeDashboard#BeforeDashboard': BeforeDashboard_1a7510af427896d367a49dbf838d2de6, + '@/components/BeforeLogin#BeforeLogin': BeforeLogin_8a7ab0eb7ab5c511aba12e68480bfe5e, } diff --git a/templates/ecommerce/src/payload-types.ts b/templates/ecommerce/src/payload-types.ts index d0e20f3e45c..a686e2d349f 100644 --- a/templates/ecommerce/src/payload-types.ts +++ b/templates/ecommerce/src/payload-types.ts @@ -127,6 +127,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: { header: Header; footer: Footer; diff --git a/templates/website/.cursor/rules/access-control-advanced.md b/templates/website/.cursor/rules/access-control-advanced.md new file mode 100644 index 00000000000..68f52fd1287 --- /dev/null +++ b/templates/website/.cursor/rules/access-control-advanced.md @@ -0,0 +1,519 @@ +--- +title: Access Control - Advanced Patterns +description: Context-aware, time-based, subscription-based access, factory functions, templates +tags: [payload, access-control, security, advanced, performance] +priority: high +--- + +# Advanced Access Control Patterns + +Advanced access control patterns including context-aware access, time-based restrictions, factory functions, and production templates. + +## Context-Aware Access Patterns + +### Locale-Specific Access + +```typescript +import type { Access } from 'payload' + +export const localeSpecificAccess: Access = ({ req: { user, locale } }) => { + // Authenticated users can access all locales + if (user) return true + + // Public users can only access English content + if (locale === 'en') return true + + return false +} +``` + +### Device-Specific Access + +```typescript +export const mobileOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return /mobile|android|iphone/i.test(userAgent) +} + +export const desktopOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return !/mobile|android|iphone/i.test(userAgent) +} +``` + +### IP-Based Access + +```typescript +export const restrictedIpAccess = (allowedIps: string[]): Access => { + return ({ req: { headers } }) => { + const ip = headers?.get('x-forwarded-for') || headers?.get('x-real-ip') + return allowedIps.includes(ip || '') + } +} + +// Usage +const internalIps = ['192.168.1.0/24', '10.0.0.5'] + +export const InternalDocs: CollectionConfig = { + slug: 'internal-docs', + access: { + read: restrictedIpAccess(internalIps), + }, +} +``` + +## Time-Based Access Patterns + +### Today's Records Only + +```typescript +export const todayOnlyAccess: Access = ({ req: { user } }) => { + if (!user) return false + + const now = new Date() + const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000) + + return { + createdAt: { + greater_than_equal: startOfDay.toISOString(), + less_than: endOfDay.toISOString(), + }, + } +} +``` + +### Recent Records (Last N Days) + +```typescript +export const recentRecordsAccess = (days: number): Access => { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - days) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} + +// Usage: Users see only last 30 days, admins see all +export const Logs: CollectionConfig = { + slug: 'logs', + access: { + read: recentRecordsAccess(30), + }, +} +``` + +### Scheduled Content (Publish Date Range) + +```typescript +export const scheduledContentAccess: Access = ({ req: { user } }) => { + // Editors see all content + if (user?.roles?.includes('admin') || user?.roles?.includes('editor')) { + return true + } + + const now = new Date().toISOString() + + // Public sees only content within publish window + return { + and: [ + { publishDate: { less_than_equal: now } }, + { + or: [{ unpublishDate: { exists: false } }, { unpublishDate: { greater_than: now } }], + }, + ], + } +} +``` + +## Subscription-Based Access + +### Active Subscription Required + +```typescript +export const activeSubscriptionAccess: Access = async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + return subscription?.status === 'active' + } catch { + return false + } +} +``` + +### Subscription Tier-Based Access + +```typescript +export const tierBasedAccess = (requiredTier: string): Access => { + const tierHierarchy = ['free', 'basic', 'pro', 'enterprise'] + + return async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + if (subscription?.status !== 'active') return false + + const userTierIndex = tierHierarchy.indexOf(subscription.tier) + const requiredTierIndex = tierHierarchy.indexOf(requiredTier) + + return userTierIndex >= requiredTierIndex + } catch { + return false + } + } +} + +// Usage +export const EnterpriseFeatures: CollectionConfig = { + slug: 'enterprise-features', + access: { + read: tierBasedAccess('enterprise'), + }, +} +``` + +## Factory Functions + +### createRoleBasedAccess + +```typescript +export function createRoleBasedAccess(roles: string[]): Access { + return ({ req: { user } }) => { + if (!user) return false + return roles.some((role) => user.roles?.includes(role)) + } +} + +// Usage +const adminOrEditor = createRoleBasedAccess(['admin', 'editor']) +const moderatorAccess = createRoleBasedAccess(['admin', 'moderator']) +``` + +### createOrgScopedAccess + +```typescript +export function createOrgScopedAccess(allowAdmin = true): Access { + return ({ req: { user } }) => { + if (!user) return false + if (allowAdmin && user.roles?.includes('admin')) return true + + return { + organizationId: { in: user.organizationIds || [] }, + } + } +} + +// Usage +const orgScoped = createOrgScopedAccess() // Admins bypass +const strictOrgScoped = createOrgScopedAccess(false) // Admins also scoped +``` + +### createTeamBasedAccess + +```typescript +export function createTeamBasedAccess(teamField = 'teamId'): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + [teamField]: { in: user.teamIds || [] }, + } + } +} +``` + +### createTimeLimitedAccess + +```typescript +export function createTimeLimitedAccess(daysAccess: number): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - daysAccess) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} +``` + +## Configuration Templates + +### Public + Authenticated Collection + +```typescript +export const PublicAuthCollection: CollectionConfig = { + slug: 'posts', + access: { + // Only admins/editors can create + create: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Authenticated users see all, public sees only published + read: ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } + }, + + // Only admins/editors can update + update: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Only admins can delete + delete: ({ req: { user } }) => { + return user?.roles?.includes('admin') || false + }, + }, + versions: { + drafts: true, + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'content', type: 'richText', required: true }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], +} +``` + +### Self-Service Collection + +```typescript +export const SelfServiceCollection: CollectionConfig = { + slug: 'users', + auth: true, + access: { + // Admins can create users + create: ({ req: { user } }) => user?.roles?.includes('admin') || false, + + // Anyone can read user profiles + read: () => true, + + // Users can update self, admins can update anyone + update: ({ req: { user }, id }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + return user.id === id + }, + + // Only admins can delete + delete: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + fields: [ + { name: 'name', type: 'text', required: true }, + { name: 'email', type: 'email', required: true }, + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + access: { + // Only admins can read/update roles + read: ({ req: { user } }) => user?.roles?.includes('admin') || false, + update: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + }, + ], +} +``` + +## Performance Considerations + +### Avoid Async Operations in Hot Paths + +```typescript +// ❌ Slow: Multiple sequential async calls +export const slowAccess: Access = async ({ req: { user } }) => { + const org = await req.payload.findByID({ collection: 'orgs', id: user.orgId }) + const team = await req.payload.findByID({ collection: 'teams', id: user.teamId }) + const subscription = await req.payload.findByID({ collection: 'subs', id: user.subId }) + + return org.active && team.active && subscription.active +} + +// ✅ Fast: Use query constraints or cache in context +export const fastAccess: Access = ({ req: { user, context } }) => { + // Cache expensive lookups + if (!context.orgStatus) { + context.orgStatus = checkOrgStatus(user.orgId) + } + + return context.orgStatus +} +``` + +### Query Constraint Optimization + +```typescript +// ❌ Avoid: Non-indexed fields in constraints +export const slowQuery: Access = () => ({ + 'metadata.internalCode': { equals: 'ABC123' }, // Slow if not indexed +}) + +// ✅ Better: Use indexed fields +export const fastQuery: Access = () => ({ + status: { equals: 'active' }, // Indexed field + organizationId: { in: ['org1', 'org2'] }, // Indexed field +}) +``` + +### Field Access on Large Arrays + +```typescript +// ❌ Slow: Complex access on array fields +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: async ({ req }) => { + // Async call runs for EVERY array item + const result = await expensiveCheck() + return result + }, + }, + }, + ], +} + +// ✅ Fast: Simple checks or cache result +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: ({ req: { user }, context }) => { + // Cache once, reuse for all items + if (context.canReadSecret === undefined) { + context.canReadSecret = user?.roles?.includes('admin') + } + return context.canReadSecret + }, + }, + }, + ], +} +``` + +### Avoid N+1 Queries + +```typescript +// ❌ N+1 Problem: Query per access check +export const n1Access: Access = async ({ req, id }) => { + // Runs for EACH document in list + const doc = await req.payload.findByID({ collection: 'docs', id }) + return doc.isPublic +} + +// ✅ Better: Use query constraint to filter at DB level +export const efficientAccess: Access = () => { + return { isPublic: { equals: true } } +} +``` + +## Debugging Tips + +### Log Access Check Execution + +```typescript +export const debugAccess: Access = ({ req: { user }, id }) => { + console.log('Access check:', { + userId: user?.id, + userRoles: user?.roles, + docId: id, + timestamp: new Date().toISOString(), + }) + return true +} +``` + +### Verify Arguments Availability + +```typescript +export const checkArgsAccess: Access = (args) => { + console.log('Available arguments:', { + hasReq: 'req' in args, + hasUser: args.req?.user ? 'yes' : 'no', + hasId: args.id ? 'provided' : 'undefined', + hasData: args.data ? 'provided' : 'undefined', + }) + return true +} +``` + +### Test Access Without User + +```typescript +// In test/development +const testAccess = await payload.find({ + collection: 'posts', + overrideAccess: false, // Enforce access control + user: undefined, // Simulate no user +}) + +console.log('Public access result:', testAccess.docs.length) +``` + +## Best Practices + +1. **Default Deny**: Start with restrictive access, gradually add permissions +2. **Type Guards**: Use TypeScript for user type safety +3. **Validate Data**: Never trust frontend-provided IDs or data +4. **Async for Critical Checks**: Use async operations for important security decisions +5. **Consistent Logic**: Apply same rules at field and collection levels +6. **Test Edge Cases**: Test with no user, wrong user, admin user scenarios +7. **Monitor Access**: Log failed access attempts for security review +8. **Regular Audit**: Review access rules quarterly or after major changes +9. **Cache Wisely**: Use `req.context` for expensive operations +10. **Document Intent**: Add comments explaining complex access rules +11. **Avoid Secrets in Client**: Never expose sensitive logic to client-side +12. **Handle Errors Gracefully**: Access functions should return `false` on error, not throw +13. **Test Local API**: Remember to set `overrideAccess: false` when testing +14. **Consider Performance**: Measure impact of async operations +15. **Principle of Least Privilege**: Grant minimum access required + +## Performance Summary + +**Minimize Async Operations**: Use query constraints over async lookups when possible + +**Cache Expensive Checks**: Store results in `req.context` for reuse + +**Index Query Fields**: Ensure fields in query constraints are indexed + +**Avoid Complex Logic in Array Fields**: Simple boolean checks preferred + +**Use Query Constraints**: Let database filter rather than loading all records diff --git a/templates/website/.cursor/rules/access-control.md b/templates/website/.cursor/rules/access-control.md new file mode 100644 index 00000000000..7b9a0a4ba5c --- /dev/null +++ b/templates/website/.cursor/rules/access-control.md @@ -0,0 +1,225 @@ +--- +title: Access Control +description: Collection, field, and global access control patterns +tags: [payload, access-control, security, permissions, rbac] +--- + +# Payload CMS Access Control + +## Access Control Layers + +1. **Collection-Level**: Controls operations on entire documents (create, read, update, delete, admin) +2. **Field-Level**: Controls access to individual fields (create, read, update) +3. **Global-Level**: Controls access to global documents (read, update) + +## Collection Access Control + +```typescript +import type { Access } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + // Boolean: Only authenticated users can create + create: ({ req: { user } }) => Boolean(user), + + // Query constraint: Public sees published, users see all + read: ({ req: { user } }) => { + if (user) return true + return { status: { equals: 'published' } } + }, + + // User-specific: Admins or document owner + update: ({ req: { user }, id }) => { + if (user?.roles?.includes('admin')) return true + return { author: { equals: user?.id } } + }, + + // Async: Check related data + delete: async ({ req, id }) => { + const hasComments = await req.payload.count({ + collection: 'comments', + where: { post: { equals: id } }, + }) + return hasComments === 0 + }, + }, +} +``` + +## Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Row-Level Security + +```typescript +// Organization-scoped access +export const organizationScoped: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + + // Users see only their organization's data + return { + organization: { + equals: user?.organization, + }, + } +} + +// Team-based access +export const teamMemberAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + 'team.members': { + contains: user.id, + }, + } +} +``` + +## Field Access Control + +**Field access ONLY returns boolean** (no query constraints). + +```typescript +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +## RBAC Pattern + +Payload does NOT provide a roles system by default. Add a `roles` field to your auth collection: + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Multi-Tenant Access Control + +```typescript +interface User { + id: string + tenantId: string + roles?: string[] +} + +const tenantAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('super-admin')) return true + + return { + tenant: { + equals: (user as User).tenantId, + }, + } +} + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + create: tenantAccess, + read: tenantAccess, + update: tenantAccess, + delete: tenantAccess, + }, + fields: [ + { + name: 'tenant', + type: 'text', + required: true, + access: { + update: ({ req: { user } }) => user?.roles?.includes('super-admin'), + }, + hooks: { + beforeChange: [ + ({ req, operation, value }) => { + if (operation === 'create' && !value) { + return (req.user as User)?.tenantId + } + return value + }, + ], + }, + }, + ], +} +``` + +## Important Notes + +1. **Local API Default**: Access control is **skipped by default** in Local API (`overrideAccess: true`). When passing a `user` parameter, you must set `overrideAccess: false`: + +```typescript +// ❌ WRONG: Passes user but bypasses access control +await payload.find({ + collection: 'posts', + user: someUser, +}) + +// ✅ CORRECT: Respects the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // Required to enforce access control +}) +``` + +2. **Field Access Limitations**: Field-level access does NOT support query constraints - only boolean returns. + +3. **Admin Panel Visibility**: The `admin` access control determines if a collection appears in the admin panel for a user. diff --git a/templates/website/.cursor/rules/adapters.md b/templates/website/.cursor/rules/adapters.md new file mode 100644 index 00000000000..49b8b3367fc --- /dev/null +++ b/templates/website/.cursor/rules/adapters.md @@ -0,0 +1,209 @@ +--- +title: Database Adapters & Transactions +description: Database adapters, storage, email, and transaction patterns +tags: [payload, database, mongodb, postgres, sqlite, transactions] +--- + +# Payload CMS Adapters + +## Database Adapters + +### MongoDB + +```typescript +import { mongooseAdapter } from '@payloadcms/db-mongodb' + +export default buildConfig({ + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +### Postgres + +```typescript +import { postgresAdapter } from '@payloadcms/db-postgres' + +export default buildConfig({ + db: postgresAdapter({ + pool: { + connectionString: process.env.DATABASE_URI, + }, + push: false, // Don't auto-push schema changes + migrationDir: './migrations', + }), +}) +``` + +### SQLite + +```typescript +import { sqliteAdapter } from '@payloadcms/db-sqlite' + +export default buildConfig({ + db: sqliteAdapter({ + client: { + url: 'file:./payload.db', + }, + transactionOptions: {}, // Enable transactions (disabled by default) + }), +}) +``` + +## Transactions + +Payload automatically uses transactions for all-or-nothing database operations. + +### Threading req Through Operations + +**CRITICAL**: When performing nested operations in hooks, always pass `req` to maintain transaction context. + +```typescript +// ✅ CORRECT: Thread req through nested operations +const resaveChildren: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + // Find children - pass req + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + req, // Maintains transaction context + }) + + // Update each child - pass req + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + req, // Same transaction as parent operation + }) + } +} + +// ❌ WRONG: Missing req breaks transaction +const brokenHook: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + // Missing req - separate transaction or no transaction + }) + + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + // Missing req - if parent operation fails, these updates persist + }) + } +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +### Manual Transaction Control + +```typescript +const transactionID = await payload.db.beginTransaction() +try { + await payload.create({ + collection: 'orders', + data: orderData, + req: { transactionID }, + }) + await payload.update({ + collection: 'inventory', + id: itemId, + data: { stock: newStock }, + req: { transactionID }, + }) + await payload.db.commitTransaction(transactionID) +} catch (error) { + await payload.db.rollbackTransaction(transactionID) + throw error +} +``` + +## Storage Adapters + +Available storage adapters: + +- **@payloadcms/storage-s3** - AWS S3 +- **@payloadcms/storage-azure** - Azure Blob Storage +- **@payloadcms/storage-gcs** - Google Cloud Storage +- **@payloadcms/storage-r2** - Cloudflare R2 +- **@payloadcms/storage-vercel-blob** - Vercel Blob +- **@payloadcms/storage-uploadthing** - Uploadthing + +### AWS S3 + +```typescript +import { s3Storage } from '@payloadcms/storage-s3' + +export default buildConfig({ + plugins: [ + s3Storage({ + collections: { + media: true, + }, + bucket: process.env.S3_BUCKET, + config: { + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + region: process.env.S3_REGION, + }, + }), + ], +}) +``` + +## Email Adapters + +### Nodemailer (SMTP) + +```typescript +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' + +export default buildConfig({ + email: nodemailerAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + transportOptions: { + host: process.env.SMTP_HOST, + port: 587, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }, + }), +}) +``` + +### Resend + +```typescript +import { resendAdapter } from '@payloadcms/email-resend' + +export default buildConfig({ + email: resendAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + apiKey: process.env.RESEND_API_KEY, + }), +}) +``` + +## Important Notes + +1. **MongoDB Transactions**: Require replica set configuration +2. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +3. **Pass req**: Always pass `req` to nested operations in hooks for transaction safety +4. **Point Fields**: Not supported in SQLite diff --git a/templates/website/.cursor/rules/collections.md b/templates/website/.cursor/rules/collections.md new file mode 100644 index 00000000000..af625108e60 --- /dev/null +++ b/templates/website/.cursor/rules/collections.md @@ -0,0 +1,171 @@ +--- +title: Collections +description: Collection configurations and patterns +tags: [payload, collections, auth, upload, drafts] +--- + +# Payload CMS Collections + +## Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +## Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Upload Collection + +```typescript +export const Media: CollectionConfig = { + slug: 'media', + upload: { + staticDir: 'media', + mimeTypes: ['image/*'], + imageSizes: [ + { + name: 'thumbnail', + width: 400, + height: 300, + position: 'centre', + }, + { + name: 'card', + width: 768, + height: 1024, + }, + ], + adminThumbnail: 'thumbnail', + focalPoint: true, + crop: true, + }, + access: { + read: () => true, + }, + fields: [ + { + name: 'alt', + type: 'text', + required: true, + }, + ], +} +``` + +## Versioning & Drafts + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} +``` + +### Draft API Usage + +```typescript +// Create draft +await payload.create({ + collection: 'posts', + data: { title: 'Draft Post' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft version if exists +}) +``` + +## Globals + +Globals are single-instance documents (not collections). + +```typescript +import type { GlobalConfig } from 'payload' + +export const Header: GlobalConfig = { + slug: 'header', + label: 'Header', + admin: { + group: 'Settings', + }, + fields: [ + { + name: 'logo', + type: 'upload', + relationTo: 'media', + required: true, + }, + { + name: 'nav', + type: 'array', + maxRows: 8, + fields: [ + { + name: 'link', + type: 'relationship', + relationTo: 'pages', + }, + { + name: 'label', + type: 'text', + }, + ], + }, + ], +} +``` diff --git a/templates/website/.cursor/rules/components.md b/templates/website/.cursor/rules/components.md new file mode 100644 index 00000000000..8610b8d7b33 --- /dev/null +++ b/templates/website/.cursor/rules/components.md @@ -0,0 +1,794 @@ +# Custom Components in Payload CMS + +Custom Components allow you to fully customize the Admin Panel by swapping in your own React components. You can replace nearly every part of the interface or add entirely new functionality. + +## Component Types + +There are four main types of Custom Components: + +1. **Root Components** - Affect the Admin Panel globally (logo, nav, header) +2. **Collection Components** - Specific to collection views +3. **Global Components** - Specific to global document views +4. **Field Components** - Custom field UI and cells + +## Defining Custom Components + +### Component Paths + +Components are defined using file paths (not direct imports) to keep the config lightweight and Node.js compatible. + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + logout: { + Button: '/src/components/Logout#MyComponent', // Named export + }, + Nav: '/src/components/Nav', // Default export + }, + }, +}) +``` + +**Component Path Rules:** + +1. Paths are relative to project root (or `config.admin.importMap.baseDir`) +2. For **named exports**: append `#ExportName` or use `exportName` property +3. For **default exports**: no suffix needed +4. File extensions can be omitted + +### Component Config Object + +Instead of a string path, you can pass a config object: + +```typescript +{ + logout: { + Button: { + path: '/src/components/Logout', + exportName: 'MyComponent', + clientProps: { customProp: 'value' }, + serverProps: { asyncData: someData }, + }, + }, +} +``` + +**Config Properties:** + +| Property | Description | +| ------------- | ----------------------------------------------------- | +| `path` | File path to component (named exports via `#`) | +| `exportName` | Named export (alternative to `#` in path) | +| `clientProps` | Props for Client Components (must be serializable) | +| `serverProps` | Props for Server Components (can be non-serializable) | + +### Setting Base Directory + +```typescript +import path from 'path' +import { fileURLToPath } from 'node:url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), // Set base directory + }, + components: { + Nav: '/components/Nav', // Now relative to src/ + }, + }, +}) +``` + +## Server vs Client Components + +**All components are React Server Components by default.** + +### Server Components (Default) + +Can use Local API directly, perform async operations, and access full Payload instance. + +```tsx +import React from 'react' +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const page = await payload.findByID({ + collection: 'pages', + id: '123', + }) + + return

{page.title}

+} + +export default MyServerComponent +``` + +### Client Components + +Use the `'use client'` directive for interactivity, hooks, state, etc. + +```tsx +'use client' +import React, { useState } from 'react' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + + return +} +``` + +**Important:** Client Components cannot receive non-serializable props (functions, class instances, etc.). Payload automatically strips these when passing to client components. + +## Default Props + +All Custom Components receive these props by default: + +| Prop | Description | Type | +| --------- | ---------------------------------------- | --------- | +| `payload` | Payload instance (Local API access) | `Payload` | +| `i18n` | Internationalization object | `I18n` | +| `locale` | Current locale (if localization enabled) | `string` | + +**Server Component Example:** + +```tsx +async function MyComponent({ payload, i18n, locale }) { + const data = await payload.find({ + collection: 'posts', + locale, + }) + + return
{data.docs.length} posts
+} +``` + +**Client Component Example:** + +```tsx +'use client' +import { usePayload, useLocale, useTranslation } from '@payloadcms/ui' + +export function MyComponent() { + // Access via hooks in client components + const { getLocal, getByID } = usePayload() + const locale = useLocale() + const { t, i18n } = useTranslation() + + return
{t('myKey')}
+} +``` + +## Custom Props + +Pass additional props using `clientProps` or `serverProps`: + +```typescript +{ + logout: { + Button: { + path: '/components/Logout', + clientProps: { + buttonText: 'Sign Out', + onLogout: () => console.log('Logged out'), + }, + }, + }, +} +``` + +Receive in component: + +```tsx +'use client' +export function Logout({ buttonText, onLogout }) { + return +} +``` + +## Root Components + +Root Components affect the entire Admin Panel. + +### Available Root Components + +| Component | Description | Config Path | +| ----------------- | -------------------------------- | ---------------------------------- | +| `Nav` | Entire navigation sidebar | `admin.components.Nav` | +| `graphics.Icon` | Small icon (used in nav) | `admin.components.graphics.Icon` | +| `graphics.Logo` | Full logo (used on login) | `admin.components.graphics.Logo` | +| `logout.Button` | Logout button | `admin.components.logout.Button` | +| `actions` | Header actions (array) | `admin.components.actions` | +| `header` | Above header (array) | `admin.components.header` | +| `beforeDashboard` | Before dashboard content (array) | `admin.components.beforeDashboard` | +| `afterDashboard` | After dashboard content (array) | `admin.components.afterDashboard` | +| `beforeLogin` | Before login form (array) | `admin.components.beforeLogin` | +| `afterLogin` | After login form (array) | `admin.components.afterLogin` | +| `beforeNavLinks` | Before nav links (array) | `admin.components.beforeNavLinks` | +| `afterNavLinks` | After nav links (array) | `admin.components.afterNavLinks` | +| `settingsMenu` | Settings menu items (array) | `admin.components.settingsMenu` | +| `providers` | Custom React Context providers | `admin.components.providers` | +| `views` | Custom views (dashboard, etc.) | `admin.components.views` | + +### Example: Custom Logo + +```typescript +export default buildConfig({ + admin: { + components: { + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + }, + }, +}) +``` + +```tsx +// components/Logo.tsx +export default function Logo() { + return My Brand +} +``` + +### Example: Header Actions + +```typescript +export default buildConfig({ + admin: { + components: { + actions: ['/components/ClearCacheButton', '/components/PreviewButton'], + }, + }, +}) +``` + +```tsx +// components/ClearCacheButton.tsx +'use client' +export default function ClearCacheButton() { + return ( + + ) +} +``` + +## Collection Components + +Collection Components are specific to a collection's views. + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view components + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/CustomSaveDraft', + PublishButton: '/components/CustomPublish', + }, + + // List view components + list: { + Header: '/components/PostsListHeader', + beforeList: ['/components/ListFilters'], + afterList: ['/components/ListFooter'], + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Global Components + +Similar to Collection Components but for Global documents. + +```typescript +import type { GlobalConfig } from 'payload' + +export const Settings: GlobalConfig = { + slug: 'settings', + admin: { + components: { + edit: { + PreviewButton: '/components/SettingsPreview', + SaveButton: '/components/SettingsSave', + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Field Components + +Customize how fields render in Edit and List views. + +### Field Component (Edit View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Field: '/components/StatusField', + }, + }, +} +``` + +```tsx +// components/StatusField.tsx +'use client' +import { useField } from '@payloadcms/ui' +import type { SelectFieldClientComponent } from 'payload' + +export const StatusField: SelectFieldClientComponent = ({ path, field }) => { + const { value, setValue } = useField({ path }) + + return ( +
+ + +
+ ) +} +``` + +### Cell Component (List View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Cell: '/components/StatusCell', + }, + }, +} +``` + +```tsx +// components/StatusCell.tsx +import type { SelectFieldCellComponent } from 'payload' + +export const StatusCell: SelectFieldCellComponent = ({ data, cellData }) => { + const isPublished = cellData === 'published' + + return ( + + {cellData} + + ) +} +``` + +### UI Field (Presentational Only) + +Special field type for adding custom UI without affecting data: + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +```tsx +// components/RefundButton.tsx +'use client' +import { useDocumentInfo } from '@payloadcms/ui' + +export default function RefundButton() { + const { id } = useDocumentInfo() + + return ( + + ) +} +``` + +## Using Hooks + +Payload provides many React hooks for Client Components: + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Current document info (id, slug, etc.) + useField, // Field value and setValue + useForm, // Form state and dispatch + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +**Important:** These hooks only work in Client Components within the Admin Panel context. + +## Accessing Payload Config + +**In Server Components:** + +```tsx +async function MyServerComponent({ payload }) { + const { config } = payload + return
{config.serverURL}
+} +``` + +**In Client Components:** + +```tsx +'use client' +import { useConfig } from '@payloadcms/ui' + +export function MyClientComponent() { + const { config } = useConfig() // Client-safe config + return
{config.serverURL}
+} +``` + +**Important:** Client Components receive a serializable version of the config (functions, validation, etc. are stripped). + +## Field Config Access + +**Server Component:** + +```tsx +import type { TextFieldServerComponent } from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = ({ field }) => { + return
Field name: {field.name}
+} +``` + +**Client Component:** + +```tsx +'use client' +import type { TextFieldClientComponent } from 'payload' + +export const MyFieldComponent: TextFieldClientComponent = ({ clientField }) => { + // clientField has non-serializable props removed + return
Field name: {clientField.name}
+} +``` + +## Translations (i18n) + +**Server Component:** + +```tsx +import { getTranslation } from '@payloadcms/translations' + +async function MyServerComponent({ i18n }) { + const translatedTitle = getTranslation(myTranslation, i18n) + return

{translatedTitle}

+} +``` + +**Client Component:** + +```tsx +'use client' +import { useTranslation } from '@payloadcms/ui' + +export function MyClientComponent() { + const { t, i18n } = useTranslation() + + return ( +
+

{t('namespace:key', { variable: 'value' })}

+

Language: {i18n.language}

+
+ ) +} +``` + +## Styling Components + +### Using CSS Variables + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Custom Component
+} +``` + +```scss +// styles.scss +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} +``` + +### Importing Payload SCSS + +```scss +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +## Common Patterns + +### Conditional Field Visibility + +```tsx +'use client' +import { useFormFields } from '@payloadcms/ui' +import type { TextFieldClientComponent } from 'payload' + +export const ConditionalField: TextFieldClientComponent = ({ path }) => { + const showField = useFormFields(([fields]) => fields.enableFeature?.value) + + if (!showField) return null + + return +} +``` + +### Loading Data from API + +```tsx +'use client' +import { useState, useEffect } from 'react' + +export function DataLoader() { + const [data, setData] = useState(null) + + useEffect(() => { + fetch('/api/custom-data') + .then((res) => res.json()) + .then(setData) + }, []) + + return
{JSON.stringify(data)}
+} +``` + +### Using Local API in Server Components + +```tsx +import type { Payload } from 'payload' + +async function RelatedPosts({ payload, id }: { payload: Payload; id: string }) { + const post = await payload.findByID({ + collection: 'posts', + id, + depth: 0, + }) + + const related = await payload.find({ + collection: 'posts', + where: { + category: { equals: post.category }, + id: { not_equals: id }, + }, + limit: 5, + }) + + return ( +
+

Related Posts

+
    + {related.docs.map((doc) => ( +
  • {doc.title}
  • + ))} +
+
+ ) +} + +export default RelatedPosts +``` + +## Performance Best Practices + +### 1. Minimize Client Bundle Size + +```tsx +// ❌ BAD: Imports entire package +'use client' +import { Button } from '@payloadcms/ui' + +// ✅ GOOD: Tree-shakeable import for frontend +import { Button } from '@payloadcms/ui/elements/Button' +``` + +**Rule:** In Admin Panel UI, import from `@payloadcms/ui`. In frontend code, use specific paths. + +### 2. Optimize Re-renders + +```tsx +// ❌ BAD: Re-renders on every form change +'use client' +import { useForm } from '@payloadcms/ui' + +export function MyComponent() { + const { fields } = useForm() + // Re-renders on ANY field change +} + +// ✅ GOOD: Only re-renders when specific field changes +;('use client') +import { useFormFields } from '@payloadcms/ui' + +export function MyComponent({ path }) { + const value = useFormFields(([fields]) => fields[path]) + // Only re-renders when this field changes +} +``` + +### 3. Use Server Components When Possible + +```tsx +// ✅ GOOD: No JavaScript sent to client +async function PostCount({ payload }) { + const { totalDocs } = await payload.find({ + collection: 'posts', + limit: 0, + }) + + return

{totalDocs} posts

+} + +// Only use client components when you need: +// - State (useState, useReducer) +// - Effects (useEffect) +// - Event handlers (onClick, onChange) +// - Browser APIs (localStorage, window) +``` + +### 4. React Best Practices + +- Use React.memo() for expensive components +- Implement proper key props in lists +- Avoid inline function definitions in renders +- Use Suspense boundaries for async operations + +## Import Map + +Payload generates an import map at `app/(payload)/admin/importMap.js` that resolves all component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Override location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Type Safety + +Use Payload's TypeScript types for components: + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, +} from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = (props) => { + // Fully typed props +} +``` + +## Troubleshooting + +### "useConfig is undefined" or similar hook errors + +**Cause:** Dependency version mismatch between Payload packages. + +**Solution:** Pin all `@payloadcms/*` packages to the exact same version: + +```json +{ + "dependencies": { + "payload": "3.0.0", + "@payloadcms/ui": "3.0.0", + "@payloadcms/richtext-lexical": "3.0.0" + } +} +``` + +### Component not loading + +1. Check file path is correct (relative to baseDir) +2. Verify named export syntax: `/path/to/file#ExportName` +3. Run `payload generate:importmap` to regenerate +4. Check for TypeScript errors in component file + +## Resources + +- [Custom Components Docs](https://payloadcms.com/docs/custom-components/overview) +- [Root Components](https://payloadcms.com/docs/custom-components/root-components) +- [Custom Views](https://payloadcms.com/docs/custom-components/custom-views) +- [React Hooks](https://payloadcms.com/docs/admin/react-hooks) +- [Custom CSS](https://payloadcms.com/docs/admin/customizing-css) diff --git a/templates/website/.cursor/rules/endpoints.md b/templates/website/.cursor/rules/endpoints.md new file mode 100644 index 00000000000..8a2481dbe5d --- /dev/null +++ b/templates/website/.cursor/rules/endpoints.md @@ -0,0 +1,236 @@ +--- +title: Custom Endpoints +description: Custom REST API endpoints with authentication and helpers +tags: [payload, endpoints, api, routes, webhooks] +--- + +# Payload Custom Endpoints + +## Basic Endpoint Pattern + +Custom endpoints are **not authenticated by default**. Always check `req.user`. + +```typescript +import { APIError } from 'payload' +import type { Endpoint } from 'payload' + +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} +``` + +## Route Parameters + +```typescript +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Request Body Handling + +```typescript +// Manual JSON parsing +export const createEndpoint: Endpoint = { + path: '/create', + method: 'post', + handler: async (req) => { + const data = await req.json() + + const result = await req.payload.create({ + collection: 'posts', + data, + }) + + return Response.json(result) + }, +} + +// Using helper (handles JSON + files) +import { addDataAndFileToRequest } from 'payload' + +export const uploadEndpoint: Endpoint = { + path: '/upload', + method: 'post', + handler: async (req) => { + await addDataAndFileToRequest(req) + + // req.data contains parsed body + // req.file contains uploaded file (if multipart) + + const result = await req.payload.create({ + collection: 'media', + data: req.data, + file: req.file, + }) + + return Response.json(result) + }, +} +``` + +## Query Parameters + +```typescript +export const searchEndpoint: Endpoint = { + path: '/search', + method: 'get', + handler: async (req) => { + const url = new URL(req.url) + const query = url.searchParams.get('q') + const limit = parseInt(url.searchParams.get('limit') || '10') + + const results = await req.payload.find({ + collection: 'posts', + where: { + title: { + contains: query, + }, + }, + limit, + }) + + return Response.json(results) + }, +} +``` + +## CORS Headers + +```typescript +import { headersWithCors } from 'payload' + +export const corsEndpoint: Endpoint = { + path: '/public-data', + method: 'get', + handler: async (req) => { + const data = await fetchPublicData() + + return Response.json(data, { + headers: headersWithCors({ + headers: new Headers(), + req, + }), + }) + }, +} +``` + +## Error Handling + +```typescript +import { APIError } from 'payload' + +export const validateEndpoint: Endpoint = { + path: '/validate', + method: 'post', + handler: async (req) => { + const data = await req.json() + + if (!data.email) { + throw new APIError('Email is required', 400) + } + + return Response.json({ valid: true }) + }, +} +``` + +## Endpoint Placement + +### Collection Endpoints + +Mounted at `/api/{collection-slug}/{path}`. + +```typescript +export const Orders: CollectionConfig = { + slug: 'orders', + endpoints: [ + { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + // Available at: /api/orders/:id/tracking + const orderId = req.routeParams.id + return Response.json({ orderId }) + }, + }, + ], +} +``` + +### Global Endpoints + +Mounted at `/api/globals/{global-slug}/{path}`. + +```typescript +export const Settings: GlobalConfig = { + slug: 'settings', + endpoints: [ + { + path: '/clear-cache', + method: 'post', + handler: async (req) => { + // Available at: /api/globals/settings/clear-cache + await clearCache() + return Response.json({ message: 'Cache cleared' }) + }, + }, + ], +} +``` + +### Root Endpoints + +Mounted at `/api/{path}`. + +```typescript +export default buildConfig({ + endpoints: [ + { + path: '/hello', + method: 'get', + handler: () => { + // Available at: /api/hello + return Response.json({ message: 'Hello!' }) + }, + }, + ], +}) +``` + +## Best Practices + +1. **Always check authentication** - Custom endpoints are not authenticated by default +2. **Use `req.payload` for operations** - Ensures access control and hooks execute +3. **Use helpers for common tasks** - `addDataAndFileToRequest`, `headersWithCors` +4. **Throw `APIError` for errors** - Provides consistent error responses +5. **Return Web API `Response`** - Use `Response.json()` for consistent responses +6. **Validate input** - Check required fields, validate types +7. **Log errors** - Use `req.payload.logger` for debugging diff --git a/templates/website/.cursor/rules/field-type-guards.md b/templates/website/.cursor/rules/field-type-guards.md new file mode 100644 index 00000000000..3514ad44993 --- /dev/null +++ b/templates/website/.cursor/rules/field-type-guards.md @@ -0,0 +1,230 @@ +--- +title: Field Type Guards +description: Runtime field type checking and safe type narrowing +tags: [payload, typescript, type-guards, fields] +--- + +# Payload Field Type Guards + +Type guards for runtime field type checking and safe type narrowing. + +## Most Common Guards + +### fieldAffectsData + +**Most commonly used guard.** Checks if field stores data (has name and is not UI-only). + +```typescript +import { fieldAffectsData } from 'payload' + +function generateSchema(fields: Field[]) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + // Safe to access field.name + schema[field.name] = getFieldType(field) + } + }) +} + +// Filter data fields +const dataFields = fields.filter(fieldAffectsData) +``` + +### fieldHasSubFields + +Checks if field contains nested fields (group, array, row, or collapsible). + +```typescript +import { fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[]): void { + fields.forEach((field) => { + if (fieldHasSubFields(field)) { + // Safe to access field.fields + traverseFields(field.fields) + } + }) +} +``` + +### fieldIsArrayType + +Checks if field type is `'array'`. + +```typescript +import { fieldIsArrayType } from 'payload' + +if (fieldIsArrayType(field)) { + // field.type === 'array' + console.log(`Min rows: ${field.minRows}`) + console.log(`Max rows: ${field.maxRows}`) +} +``` + +## Capability Guards + +### fieldSupportsMany + +Checks if field can have multiple values (select, relationship, or upload with `hasMany`). + +```typescript +import { fieldSupportsMany } from 'payload' + +if (fieldSupportsMany(field)) { + // field.type is 'select' | 'relationship' | 'upload' + if (field.hasMany) { + console.log('Field accepts multiple values') + } +} +``` + +### fieldHasMaxDepth + +Checks if field is relationship/upload/join with numeric `maxDepth` property. + +```typescript +import { fieldHasMaxDepth } from 'payload' + +if (fieldHasMaxDepth(field)) { + // field.type is 'upload' | 'relationship' | 'join' + // AND field.maxDepth is number + const remainingDepth = field.maxDepth - currentDepth +} +``` + +### fieldIsVirtual + +Checks if field is virtual (computed or virtual relationship). + +```typescript +import { fieldIsVirtual } from 'payload' + +if (fieldIsVirtual(field)) { + // field.virtual is truthy + if (typeof field.virtual === 'string') { + console.log(`Virtual path: ${field.virtual}`) + } +} +``` + +## Type Checking Guards + +### fieldIsBlockType + +```typescript +import { fieldIsBlockType } from 'payload' + +if (fieldIsBlockType(field)) { + // field.type === 'blocks' + field.blocks.forEach((block) => { + console.log(`Block: ${block.slug}`) + }) +} +``` + +### fieldIsGroupType + +```typescript +import { fieldIsGroupType } from 'payload' + +if (fieldIsGroupType(field)) { + // field.type === 'group' + console.log(`Interface: ${field.interfaceName}`) +} +``` + +### fieldIsPresentationalOnly + +```typescript +import { fieldIsPresentationalOnly } from 'payload' + +if (fieldIsPresentationalOnly(field)) { + // field.type === 'ui' + // Skip in data operations, GraphQL schema, etc. + return +} +``` + +## Common Patterns + +### Recursive Field Traversal + +```typescript +import { fieldAffectsData, fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[], callback: (field: Field) => void) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + callback(field) + } + + if (fieldHasSubFields(field)) { + traverseFields(field.fields, callback) + } + }) +} +``` + +### Filter Data-Bearing Fields + +```typescript +import { fieldAffectsData, fieldIsPresentationalOnly, fieldIsHiddenOrDisabled } from 'payload' + +const dataFields = fields.filter( + (field) => + fieldAffectsData(field) && !fieldIsPresentationalOnly(field) && !fieldIsHiddenOrDisabled(field), +) +``` + +### Container Type Switching + +```typescript +import { fieldIsArrayType, fieldIsBlockType, fieldHasSubFields } from 'payload' + +if (fieldIsArrayType(field)) { + // Handle array-specific logic +} else if (fieldIsBlockType(field)) { + // Handle blocks-specific logic +} else if (fieldHasSubFields(field)) { + // Handle group/row/collapsible +} +``` + +### Safe Property Access + +```typescript +import { fieldSupportsMany, fieldHasMaxDepth } from 'payload' + +// With guard - safe access +if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') +} + +if (fieldHasMaxDepth(field)) { + const depth = field.maxDepth // TypeScript knows this is number +} +``` + +## All Available Guards + +| Type Guard | Checks For | Use When | +| --------------------------- | --------------------------------- | ---------------------------------------- | +| `fieldAffectsData` | Field stores data (has name) | Need to access field data or name | +| `fieldHasSubFields` | Field contains nested fields | Recursively traverse fields | +| `fieldIsArrayType` | Field is array type | Distinguish arrays from other containers | +| `fieldIsBlockType` | Field is blocks type | Handle blocks-specific logic | +| `fieldIsGroupType` | Field is group type | Handle group-specific logic | +| `fieldSupportsMany` | Field can have multiple values | Check for `hasMany` support | +| `fieldHasMaxDepth` | Field supports depth control | Control relationship/upload/join depth | +| `fieldIsPresentationalOnly` | Field is UI-only | Exclude from data operations | +| `fieldIsSidebar` | Field positioned in sidebar | Separate sidebar rendering | +| `fieldIsID` | Field name is 'id' | Special ID field handling | +| `fieldIsHiddenOrDisabled` | Field is hidden or disabled | Filter from UI operations | +| `fieldShouldBeLocalized` | Field needs localization | Proper locale table checks | +| `fieldIsVirtual` | Field is virtual | Skip in database transforms | +| `tabHasName` | Tab is named (stores data) | Distinguish named vs unnamed tabs | +| `groupHasName` | Group is named (stores data) | Distinguish named vs unnamed groups | +| `optionIsObject` | Option is `{label, value}` | Access option properties safely | +| `optionsAreObjects` | All options are objects | Batch option processing | +| `optionIsValue` | Option is string value | Handle string options | +| `valueIsValueWithRelation` | Value is polymorphic relationship | Handle polymorphic relationships | diff --git a/templates/website/.cursor/rules/fields.md b/templates/website/.cursor/rules/fields.md new file mode 100644 index 00000000000..8468e41f599 --- /dev/null +++ b/templates/website/.cursor/rules/fields.md @@ -0,0 +1,317 @@ +--- +title: Fields +description: Field types, patterns, and configurations +tags: [payload, fields, validation, conditional] +--- + +# Payload CMS Fields + +## Common Field Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## Field Types + +### Text Field + +```typescript +{ + name: 'title', + type: 'text', + required: true, + unique: true, + minLength: 5, + maxLength: 100, + index: true, + localized: true, + defaultValue: 'Default Title', + validate: (value) => Boolean(value) || 'Required', + admin: { + placeholder: 'Enter title...', + position: 'sidebar', + condition: (data) => data.showTitle === true, + }, +} +``` + +### Rich Text (Lexical) + +```typescript +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { HeadingFeature, LinkFeature } from '@payloadcms/richtext-lexical' + +{ + name: 'content', + type: 'richText', + required: true, + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + HeadingFeature({ + enabledHeadingSizes: ['h1', 'h2', 'h3'], + }), + LinkFeature({ + enabledCollections: ['posts', 'pages'], + }), + ], + }), +} +``` + +### Relationship + +```typescript +// Single relationship +{ + name: 'author', + type: 'relationship', + relationTo: 'users', + required: true, + maxDepth: 2, +} + +// Multiple relationships (hasMany) +{ + name: 'categories', + type: 'relationship', + relationTo: 'categories', + hasMany: true, + filterOptions: { + active: { equals: true }, + }, +} + +// Polymorphic relationship +{ + name: 'relatedContent', + type: 'relationship', + relationTo: ['posts', 'pages'], + hasMany: true, +} +``` + +### Array + +```typescript +{ + name: 'slides', + type: 'array', + minRows: 2, + maxRows: 10, + labels: { + singular: 'Slide', + plural: 'Slides', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'image', + type: 'upload', + relationTo: 'media', + }, + ], + admin: { + initCollapsed: true, + }, +} +``` + +### Blocks + +```typescript +import type { Block } from 'payload' + +const HeroBlock: Block = { + slug: 'hero', + interfaceName: 'HeroBlock', + fields: [ + { + name: 'heading', + type: 'text', + required: true, + }, + { + name: 'background', + type: 'upload', + relationTo: 'media', + }, + ], +} + +const ContentBlock: Block = { + slug: 'content', + fields: [ + { + name: 'text', + type: 'richText', + }, + ], +} + +{ + name: 'layout', + type: 'blocks', + blocks: [HeroBlock, ContentBlock], +} +``` + +### Select + +```typescript +{ + name: 'status', + type: 'select', + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + ], + defaultValue: 'draft', + required: true, +} + +// Multiple select +{ + name: 'tags', + type: 'select', + hasMany: true, + options: ['tech', 'news', 'sports'], +} +``` + +### Upload + +```typescript +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + required: true, + filterOptions: { + mimeType: { contains: 'image' }, + }, +} +``` + +### Point (Geolocation) + +```typescript +{ + name: 'location', + type: 'point', + label: 'Location', + required: true, +} + +// Query by distance +const nearbyLocations = await payload.find({ + collection: 'stores', + where: { + location: { + near: [10, 20], // [longitude, latitude] + maxDistance: 5000, // in meters + minDistance: 1000, + }, + }, +}) +``` + +### Join Fields (Reverse Relationships) + +```typescript +// From Users collection - show user's orders +{ + name: 'orders', + type: 'join', + collection: 'orders', + on: 'customer', // The field in 'orders' that references this user +} +``` + +### Tabs & Groups + +```typescript +// Tabs +{ + type: 'tabs', + tabs: [ + { + label: 'Content', + fields: [ + { name: 'title', type: 'text' }, + { name: 'body', type: 'richText' }, + ], + }, + { + label: 'SEO', + fields: [ + { name: 'metaTitle', type: 'text' }, + { name: 'metaDescription', type: 'textarea' }, + ], + }, + ], +} + +// Group (named) +{ + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], +} +``` + +## Validation + +```typescript +{ + name: 'email', + type: 'email', + validate: (value, { operation, data, siblingData }) => { + if (operation === 'create' && !value) { + return 'Email is required' + } + if (value && !value.includes('@')) { + return 'Invalid email format' + } + return true + }, +} +``` diff --git a/templates/website/.cursor/rules/hooks.md b/templates/website/.cursor/rules/hooks.md new file mode 100644 index 00000000000..1f168f9eaeb --- /dev/null +++ b/templates/website/.cursor/rules/hooks.md @@ -0,0 +1,175 @@ +--- +title: Hooks +description: Collection hooks, field hooks, and context patterns +tags: [payload, hooks, lifecycle, context] +--- + +# Payload CMS Hooks + +## Collection Hooks + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Field Hooks + +```typescript +import type { FieldHook } from 'payload' + +const beforeValidateHook: FieldHook = ({ value }) => { + return value.trim().toLowerCase() +} + +const afterReadHook: FieldHook = ({ value, req }) => { + // Hide email from non-admins + if (!req.user?.roles?.includes('admin')) { + return value.replace(/(.{2})(.*)(@.*)/, '$1***$3') + } + return value +} + +{ + name: 'email', + type: 'email', + hooks: { + beforeValidate: [beforeValidateHook], + afterRead: [afterReadHook], + }, +} +``` + +## Hook Context + +Share data between hooks or control hook behavior using request context: + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + beforeChange: [ + async ({ context }) => { + context.expensiveData = await fetchExpensiveData() + }, + ], + afterChange: [ + async ({ context, doc }) => { + // Reuse from previous hook + await processData(doc, context.expensiveData) + }, + ], + }, +} +``` + +## Next.js Revalidation Pattern + +```typescript +import type { CollectionAfterChangeHook } from 'payload' +import { revalidatePath } from 'next/cache' + +export const revalidatePage: CollectionAfterChangeHook = ({ + doc, + previousDoc, + req: { payload, context }, +}) => { + if (!context.disableRevalidate) { + if (doc._status === 'published') { + const path = doc.slug === 'home' ? '/' : `/${doc.slug}` + payload.logger.info(`Revalidating page at path: ${path}`) + revalidatePath(path) + } + + // Revalidate old path if unpublished + if (previousDoc?._status === 'published' && doc._status !== 'published') { + const oldPath = previousDoc.slug === 'home' ? '/' : `/${previousDoc.slug}` + revalidatePath(oldPath) + } + } + return doc +} +``` + +## Date Field Auto-Set + +```typescript +{ + name: 'publishedOn', + type: 'date', + hooks: { + beforeChange: [ + ({ siblingData, value }) => { + if (siblingData._status === 'published' && !value) { + return new Date() + } + return value + }, + ], + }, +} +``` + +## Best Practices + +- Use `beforeValidate` for data formatting +- Use `beforeChange` for business logic +- Use `afterChange` for side effects +- Use `afterRead` for computed fields +- Store expensive operations in `context` +- Pass `req` to nested operations for transaction safety +- Use context flags to prevent infinite loops diff --git a/templates/website/.cursor/rules/payload-overview.md b/templates/website/.cursor/rules/payload-overview.md new file mode 100644 index 00000000000..290c47822ab --- /dev/null +++ b/templates/website/.cursor/rules/payload-overview.md @@ -0,0 +1,126 @@ +--- +title: Payload CMS Overview +description: Core principles and quick reference for Payload CMS development +tags: [payload, overview, quickstart] +--- + +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Quick Reference + +| Task | Solution | +| --------------------- | ---------------------------------- | +| Auto-generate slugs | `slugField()` | +| Restrict by user | Access control with query | +| Local API user ops | `user` + `overrideAccess: false` | +| Draft/publish | `versions: { drafts: true }` | +| Computed fields | `virtual: true` with afterRead | +| Conditional fields | `admin.condition` | +| Custom validation | `validate` function | +| Filter relationships | `filterOptions` on field | +| Select fields | `select` parameter | +| Auto-set dates | beforeChange hook | +| Prevent loops | `req.context` check | +| Cascading deletes | beforeDelete hook | +| Geospatial queries | `point` field with `near`/`within` | +| Reverse relationships | `join` field type | +| Query relationships | Nested property syntax | +| Complex queries | AND/OR logic | +| Transactions | Pass `req` to operations | +| Background jobs | Jobs queue with tasks | +| Custom routes | Collection custom endpoints | +| Cloud storage | Storage adapter plugins | +| Multi-language | `localization` + `localized: true` | + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/website/.cursor/rules/plugin-development.md b/templates/website/.cursor/rules/plugin-development.md new file mode 100644 index 00000000000..d92bb12fb40 --- /dev/null +++ b/templates/website/.cursor/rules/plugin-development.md @@ -0,0 +1,323 @@ +--- +title: Plugin Development +description: Creating Payload CMS plugins with TypeScript patterns +tags: [payload, plugins, architecture, patterns] +--- + +# Payload Plugin Development + +## Plugin Architecture + +Plugins are functions that receive configuration options and return a function that transforms the Payload config: + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + enabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + // Transform config here + }) +``` + +**Key Pattern:** Double arrow function (currying) + +- First function: Accepts plugin options, returns plugin function +- Second function: Accepts Payload config, returns modified config + +## Adding Fields to Collections + +```typescript +export const seoPlugin = + (options: { collections?: string[] }): Plugin => + (config: Config): Config => { + const seoFields: Field[] = [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], + }, + ] + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...seoFields], + } + } + return collection + }), + } + } +``` + +## Adding New Collections + +```typescript +export const redirectsPlugin = + (options: { overrides?: Partial }): Plugin => + (config: Config): Config => { + const redirectsCollection: CollectionConfig = { + slug: 'redirects', + access: { read: () => true }, + fields: [ + { name: 'from', type: 'text', required: true, unique: true }, + { name: 'to', type: 'text', required: true }, + ], + ...options.overrides, + } + + return { + ...config, + collections: [...(config.collections || []), redirectsCollection], + } + } +``` + +## Adding Hooks + +```typescript +const resaveChildrenHook: CollectionAfterChangeHook = async ({ doc, req, operation }) => { + if (operation === 'update') { + const children = await req.payload.find({ + collection: 'pages', + where: { parent: { equals: doc.id } }, + }) + + for (const child of children.docs) { + await req.payload.update({ + collection: 'pages', + id: child.id, + data: child, + }) + } + } + return doc +} + +export const nestedDocsPlugin = + (options: { collections: string[] }): Plugin => + (config: Config): Config => ({ + ...config, + collections: (config.collections || []).map((collection) => { + if (options.collections.includes(collection.slug)) { + return { + ...collection, + hooks: { + ...(collection.hooks || {}), + afterChange: [resaveChildrenHook, ...(collection.hooks?.afterChange || [])], + }, + } + } + return collection + }), + }) +``` + +## Adding Root-Level Endpoints + +```typescript +export const seoPlugin = + (options: { generateTitle?: (doc: any) => string }): Plugin => + (config: Config): Config => { + const generateTitleEndpoint: Endpoint = { + path: '/plugin-seo/generate-title', + method: 'post', + handler: async (req) => { + const data = await req.json?.() + const result = options.generateTitle ? options.generateTitle(data.doc) : '' + return Response.json({ result }) + }, + } + + return { + ...config, + endpoints: [...(config.endpoints ?? []), generateTitleEndpoint], + } + } +``` + +## Field Overrides with Defaults + +```typescript +type FieldsOverride = (args: { defaultFields: Field[] }) => Field[] + +interface PluginConfig { + collections?: string[] + fields?: FieldsOverride +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const defaultFields: Field[] = [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ] + + const fields = + options.fields && typeof options.fields === 'function' + ? options.fields({ defaultFields }) + : defaultFields + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...fields], + } + } + return collection + }), + } + } +``` + +## Disable Plugin Pattern + +```typescript +interface PluginConfig { + disabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + // Always add collections/fields for database schema consistency + if (!config.collections) { + config.collections = [] + } + + config.collections.push({ + slug: 'plugin-collection', + fields: [{ name: 'title', type: 'text' }], + }) + + // If disabled, return early but keep schema changes + if (options.disabled) { + return config + } + + // Add endpoints, hooks, components only when enabled + config.endpoints = [ + ...(config.endpoints ?? []), + { + path: '/my-endpoint', + method: 'get', + handler: async () => Response.json({ message: 'Hello' }), + }, + ] + + return config + } +``` + +## Admin Components + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + if (!config.admin) config.admin = {} + if (!config.admin.components) config.admin.components = {} + if (!config.admin.components.beforeDashboard) { + config.admin.components.beforeDashboard = [] + } + + // Add client component + config.admin.components.beforeDashboard.push('my-plugin-name/client#BeforeDashboardClient') + + // Add server component (RSC) + config.admin.components.beforeDashboard.push('my-plugin-name/rsc#BeforeDashboardServer') + + return config + } +``` + +## onInit Hook + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const incomingOnInit = config.onInit + + config.onInit = async (payload) => { + // IMPORTANT: Call existing onInit first + if (incomingOnInit) await incomingOnInit(payload) + + // Plugin initialization + payload.logger.info('Plugin initialized') + + // Example: Seed data + const { totalDocs } = await payload.count({ + collection: 'plugin-collection', + where: { id: { equals: 'seeded-by-plugin' } }, + }) + + if (totalDocs === 0) { + await payload.create({ + collection: 'plugin-collection', + data: { id: 'seeded-by-plugin' }, + }) + } + } + + return config + } +``` + +## Best Practices + +### Preserve Existing Config + +```typescript +// ✅ Good +collections: [...(config.collections || []), newCollection] + +// ❌ Bad +collections: [newCollection] +``` + +### Respect User Overrides + +```typescript +const collection: CollectionConfig = { + slug: 'redirects', + fields: defaultFields, + ...options.overrides, // User overrides last +} +``` + +### Hook Composition + +```typescript +hooks: { + ...collection.hooks, + afterChange: [ + myHook, + ...(collection.hooks?.afterChange || []), + ], +} +``` + +### Type Safety + +```typescript +import type { Config, Plugin, CollectionConfig, Field } from 'payload' +``` diff --git a/templates/website/.cursor/rules/queries.md b/templates/website/.cursor/rules/queries.md new file mode 100644 index 00000000000..4920ec85f09 --- /dev/null +++ b/templates/website/.cursor/rules/queries.md @@ -0,0 +1,223 @@ +--- +title: Queries +description: Local API, REST, and GraphQL query patterns +tags: [payload, queries, local-api, rest, graphql] +--- + +# Payload CMS Queries + +## Query Operators + +```typescript +// Equals +{ color: { equals: 'blue' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater/less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In/not in +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (point fields) +{ location: { near: [10, 20, 5000] } } // [lng, lat, maxDistance] +``` + +## AND/OR Logic + +```typescript +{ + or: [ + { color: { equals: 'mint' } }, + { + and: [ + { color: { equals: 'white' } }, + { featured: { equals: false } }, + ], + }, + ], +} +``` + +## Nested Properties + +```typescript +{ + 'author.role': { equals: 'editor' }, + 'meta.featured': { exists: true }, +} +``` + +## Local API + +```typescript +// Find documents +const posts = await payload.find({ + collection: 'posts', + where: { + status: { equals: 'published' }, + 'author.name': { contains: 'john' }, + }, + depth: 2, // Populate relationships + limit: 10, + page: 1, + sort: '-createdAt', + locale: 'en', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const post = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { + status: 'published', + }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) + +// Count +const count = await payload.count({ + collection: 'posts', + where: { + status: { equals: 'published' }, + }, +}) +``` + +## Access Control in Local API + +**CRITICAL**: Local API bypasses access control by default (`overrideAccess: true`). + +```typescript +// ❌ WRONG: User is passed but access control is bypassed +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + // Result: Operation runs with ADMIN privileges +}) + +// ✅ CORRECT: Respects user's access control permissions +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + overrideAccess: false, // Required to enforce access control +}) + +// Administrative operation (intentionally bypass access control) +const allPosts = await payload.find({ + collection: 'posts', + // No user parameter, overrideAccess defaults to true +}) +``` + +**When to use `overrideAccess: false`:** + +- Performing operations on behalf of a user +- Testing access control logic +- API routes that should respect user permissions + +## REST API + +```typescript +import { stringify } from 'qs-esm' + +const query = { + status: { equals: 'published' }, +} + +const queryString = stringify( + { + where: query, + depth: 2, + limit: 10, + }, + { addQueryPrefix: true }, +) + +const response = await fetch(`https://api.example.com/api/posts${queryString}`) +const data = await response.json() +``` + +### REST Endpoints + +``` +GET /api/{collection} - Find documents +GET /api/{collection}/{id} - Find by ID +POST /api/{collection} - Create +PATCH /api/{collection}/{id} - Update +DELETE /api/{collection}/{id} - Delete +GET /api/{collection}/count - Count documents + +GET /api/globals/{slug} - Get global +POST /api/globals/{slug} - Update global +``` + +## GraphQL + +```graphql +query { + Posts(where: { status: { equals: published } }, limit: 10, sort: "-createdAt") { + docs { + id + title + author { + name + } + } + totalDocs + hasNextPage + } +} + +mutation { + createPost(data: { title: "New Post", status: draft }) { + id + title + } +} +``` + +## Performance Best Practices + +- Set `maxDepth` on relationships to prevent over-fetching +- Use `select` to limit returned fields +- Index frequently queried fields +- Use `virtual` fields for computed data +- Cache expensive operations in hook `context` diff --git a/templates/website/.cursor/rules/security-critical.mdc b/templates/website/.cursor/rules/security-critical.mdc new file mode 100644 index 00000000000..adf5d9e225d --- /dev/null +++ b/templates/website/.cursor/rules/security-critical.mdc @@ -0,0 +1,122 @@ +--- +title: Critical Security Patterns +description: The three most important security patterns in Payload CMS +tags: [payload, security, critical, access-control, transactions, hooks] +priority: high +--- + +# CRITICAL SECURITY PATTERNS + +These are the three most critical security patterns that MUST be followed in every Payload CMS project. + +## 1. Local API Access Control (MOST IMPORTANT) + +**By default, Local API operations bypass ALL access control**, even when passing a user. + +```typescript +// ❌ SECURITY BUG: Passes user but ignores their permissions +await payload.find({ + collection: 'posts', + user: someUser, // Access control is BYPASSED! +}) + +// ✅ SECURE: Actually enforces the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED for access control +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**When to use each:** + +- `overrideAccess: true` (default) - Server-side operations you trust (cron jobs, system tasks) +- `overrideAccess: false` - When operating on behalf of a user (API routes, webhooks) + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +## 2. Transaction Safety in Hooks + +**Nested operations in hooks without `req` break transaction atomicity.** + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ] +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ] +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +## 3. Prevent Infinite Hook Loops + +**Hooks triggering operations that trigger the same hooks create infinite loops.** + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ] +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ] +} +``` + +**Rule**: Use `req.context` flags to prevent hook loops diff --git a/templates/website/AGENTS.md b/templates/website/AGENTS.md new file mode 100644 index 00000000000..633b29b1f61 --- /dev/null +++ b/templates/website/AGENTS.md @@ -0,0 +1,1141 @@ +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default +6. **Access Control**: Ensure roles exist when modifiyng collection or globals with access controls + +### Code Validation + +- To validate typescript correctness after modifying code run `tsc --noEmit` +- Generate import maps after creating or modifying components. + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Configuration + +### Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Collections + +### Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +### Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Fields + +### Common Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## CRITICAL SECURITY PATTERNS + +### 1. Local API Access Control (MOST IMPORTANT) + +```typescript +// ❌ SECURITY BUG: Access control bypassed +await payload.find({ + collection: 'posts', + user: someUser, // Ignored! Operation runs with ADMIN privileges +}) + +// ✅ SECURE: Enforces user permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +### 2. Transaction Safety in Hooks + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ], +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ], +} +``` + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +### 3. Prevent Infinite Hook Loops + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ], +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ], +} +``` + +## Access Control + +### Collection-Level Access + +```typescript +import type { Access } from 'payload' + +// Boolean return +const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Query constraint (row-level security) +const ownPostsOnly: Access = ({ req: { user } }) => { + if (!user) return false + if (user?.roles?.includes('admin')) return true + + return { + author: { equals: user.id }, + } +} + +// Async access check +const projectMemberAccess: Access = async ({ req, id }) => { + const { user, payload } = req + + if (!user) return false + if (user.roles?.includes('admin')) return true + + const project = await payload.findByID({ + collection: 'projects', + id: id as string, + depth: 0, + }) + + return project.members?.includes(user.id) +} +``` + +### Field-Level Access + +```typescript +// Field access ONLY returns boolean (no query constraints) +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +### Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Hooks + +### Common Hook Patterns + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Queries + +### Local API + +```typescript +// Find with complex query +const posts = await payload.find({ + collection: 'posts', + where: { + and: [{ status: { equals: 'published' } }, { 'author.name': { contains: 'john' } }], + }, + depth: 2, // Populate relationships + limit: 10, + sort: '-createdAt', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const newPost = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { status: 'published' }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) +``` + +### Query Operators + +```typescript +// Equals +{ status: { equals: 'published' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater than / less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In array +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (geospatial) +{ location: { near: [-122.4194, 37.7749, 10000] } } +``` + +### AND/OR Logic + +```typescript +{ + or: [ + { status: { equals: 'published' } }, + { author: { equals: user.id } }, + ], +} + +{ + and: [ + { status: { equals: 'published' } }, + { featured: { equals: true } }, + ], +} +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Components + +The Admin Panel can be extensively customized using React Components. Custom Components can be Server Components (default) or Client Components. + +### Defining Components + +Components are defined using **file paths** (not direct imports) in your config: + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + // Logo and branding + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + + // Navigation + Nav: '/components/CustomNav', + beforeNavLinks: ['/components/CustomNavItem'], + afterNavLinks: ['/components/NavFooter'], + + // Header + header: ['/components/AnnouncementBanner'], + actions: ['/components/ClearCache', '/components/Preview'], + + // Dashboard + beforeDashboard: ['/components/WelcomeMessage'], + afterDashboard: ['/components/Analytics'], + + // Auth + beforeLogin: ['/components/SSOButtons'], + logout: { Button: '/components/LogoutButton' }, + + // Settings + settingsMenu: ['/components/SettingsMenu'], + + // Views + views: { + dashboard: { Component: '/components/CustomDashboard' }, + }, + }, + }, +}) +``` + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Server vs Client Components + +**All components are Server Components by default** (can use Local API directly): + +```tsx +// Server Component (default) +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const posts = await payload.find({ collection: 'posts' }) + return
{posts.totalDocs} posts
+} + +export default MyServerComponent +``` + +**Client Components** need the `'use client'` directive: + +```tsx +'use client' +import { useState } from 'react' +import { useAuth } from '@payloadcms/ui' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + const { user } = useAuth() + + return ( + + ) +} +``` + +### Using Hooks (Client Components Only) + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Document info (id, collection, etc.) + useField, // Field value and setter + useForm, // Form state + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +### Collection/Global Components + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/SaveDraft', + PublishButton: '/components/Publish', + }, + + // List view + list: { + Header: '/components/ListHeader', + beforeList: ['/components/BulkActions'], + afterList: ['/components/ListFooter'], + }, + }, + }, +} +``` + +### Field Components + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + // Edit view field + Field: '/components/StatusField', + // List view cell + Cell: '/components/StatusCell', + // Field label + Label: '/components/StatusLabel', + // Field description + Description: '/components/StatusDescription', + // Error message + Error: '/components/StatusError', + }, + }, +} +``` + +**UI Field** (presentational only, no data): + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +### Performance Best Practices + +1. **Import correctly:** + + - Admin Panel: `import { Button } from '@payloadcms/ui'` + - Frontend: `import { Button } from '@payloadcms/ui/elements/Button'` + +2. **Optimize re-renders:** + + ```tsx + // ❌ BAD: Re-renders on every form change + const { fields } = useForm() + + // ✅ GOOD: Only re-renders when specific field changes + const value = useFormFields(([fields]) => fields[path]) + ``` + +3. **Prefer Server Components** - Only use Client Components when you need: + + - State (useState, useReducer) + - Effects (useEffect) + - Event handlers (onClick, onChange) + - Browser APIs (localStorage, window) + +4. **Minimize serialized props** - Server Components serialize props sent to client + +### Styling Components + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Content
+} +``` + +```scss +// Use Payload's CSS variables +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} + +// Import Payload's SCSS library +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +### Type Safety + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, + SelectFieldServerComponent, + // ... etc +} from 'payload' + +export const MyField: TextFieldClientComponent = (props) => { + // Fully typed props +} +``` + +### Import Map + +Payload auto-generates `app/(payload)/admin/importMap.js` to resolve component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Set custom location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Custom Endpoints + +```typescript +import type { Endpoint } from 'payload' +import { APIError } from 'payload' + +// Always check authentication +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} + +// Route parameters +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Drafts & Versions + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} + +// Create draft +await payload.create({ + collection: 'pages', + data: { title: 'Draft Page' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft if available +}) +``` + +## Field Type Guards + +```typescript +import { + fieldAffectsData, + fieldHasSubFields, + fieldIsArrayType, + fieldIsBlockType, + fieldSupportsMany, + fieldHasMaxDepth, +} from 'payload' + +function processField(field: Field) { + // Check if field stores data + if (fieldAffectsData(field)) { + console.log(field.name) // Safe to access + } + + // Check if field has nested fields + if (fieldHasSubFields(field)) { + field.fields.forEach(processField) // Safe to access + } + + // Check field type + if (fieldIsArrayType(field)) { + console.log(field.minRows, field.maxRows) + } + + // Check capabilities + if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') + } +} +``` + +## Plugins + +### Using Plugins + +```typescript +import { seoPlugin } from '@payloadcms/plugin-seo' +import { redirectsPlugin } from '@payloadcms/plugin-redirects' + +export default buildConfig({ + plugins: [ + seoPlugin({ + collections: ['posts', 'pages'], + }), + redirectsPlugin({ + collections: ['pages'], + }), + ], +}) +``` + +### Creating Plugins + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + collections?: string[] + enabled?: boolean +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...collection.fields, { name: 'pluginField', type: 'text' }], + } + } + return collection + }), + }) +``` + +## Best Practices + +### Security + +1. Always set `overrideAccess: false` when passing `user` to Local API +2. Field-level access only returns boolean (no query constraints) +3. Default to restrictive access, gradually add permissions +4. Never trust client-provided data +5. Use `saveToJWT: true` for roles to avoid database lookups + +### Performance + +1. Index frequently queried fields +2. Use `select` to limit returned fields +3. Set `maxDepth` on relationships to prevent over-fetching +4. Use query constraints over async operations in access control +5. Cache expensive operations in `req.context` + +### Data Integrity + +1. Always pass `req` to nested operations in hooks +2. Use context flags to prevent infinite hook loops +3. Enable transactions for MongoDB (requires replica set) and Postgres +4. Use `beforeValidate` for data formatting +5. Use `beforeChange` for business logic + +### Type Safety + +1. Run `generate:types` after schema changes +2. Import types from generated `payload-types.ts` +3. Type your user object: `import type { User } from '@/payload-types'` +4. Use `as const` for field options +5. Use field type guards for runtime type checking + +### Organization + +1. Keep collections in separate files +2. Extract access control to `access/` directory +3. Extract hooks to `hooks/` directory +4. Use reusable field factories for common patterns +5. Document complex access control with comments + +## Common Gotchas + +1. **Local API Default**: Access control bypassed unless `overrideAccess: false` +2. **Transaction Safety**: Missing `req` in nested operations breaks atomicity +3. **Hook Loops**: Operations in hooks can trigger the same hooks +4. **Field Access**: Cannot use query constraints, only boolean +5. **Relationship Depth**: Default depth is 2, set to 0 for IDs only +6. **Draft Status**: `_status` field auto-injected when drafts enabled +7. **Type Generation**: Types not updated until `generate:types` runs +8. **MongoDB Transactions**: Require replica set configuration +9. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +10. **Point Fields**: Not supported in SQLite + +## Additional Context Files + +For deeper exploration of specific topics, refer to the context files located in `.cursor/rules/`: + +### Available Context Files + +1. **`payload-overview.md`** - High-level architecture and core concepts + + - Payload structure and initialization + - Configuration fundamentals + - Database adapters overview + +2. **`security-critical.md`** - Critical security patterns (⚠️ IMPORTANT) + + - Local API access control + - Transaction safety in hooks + - Preventing infinite hook loops + +3. **`collections.md`** - Collection configurations + + - Basic collection patterns + - Auth collections with RBAC + - Upload collections + - Drafts and versioning + - Globals + +4. **`fields.md`** - Field types and patterns + + - All field types with examples + - Conditional fields + - Virtual fields + - Field validation + - Common field patterns + +5. **`field-type-guards.md`** - TypeScript field type utilities + + - Field type checking utilities + - Safe type narrowing + - Runtime field validation + +6. **`access-control.md`** - Permission patterns + + - Collection-level access + - Field-level access + - Row-level security + - RBAC patterns + - Multi-tenant access control + +7. **`access-control-advanced.md`** - Complex access patterns + + - Nested document access + - Cross-collection permissions + - Dynamic role hierarchies + - Performance optimization + +8. **`hooks.md`** - Lifecycle hooks + + - Collection hooks + - Field hooks + - Hook context patterns + - Common hook recipes + +9. **`queries.md`** - Database operations + + - Local API usage + - Query operators + - Complex queries with AND/OR + - Performance optimization + +10. **`endpoints.md`** - Custom API endpoints + + - REST endpoint patterns + - Authentication in endpoints + - Error handling + - Route parameters + +11. **`adapters.md`** - Database and storage adapters + + - MongoDB, PostgreSQL, SQLite patterns + - Storage adapter usage (S3, Azure, GCS, etc.) + - Custom adapter development + +12. **`plugin-development.md`** - Creating plugins + + - Plugin architecture + - Modifying configuration + - Plugin hooks + - Best practices + +13. **`components.md`** - Custom Components + + - Component types (Root, Collection, Global, Field) + - Server vs Client Components + - Component paths and definition + - Default and custom props + - Using hooks + - Performance best practices + - Styling components + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/website/src/payload-types.ts b/templates/website/src/payload-types.ts index e34987e1c0d..7d83ad77977 100644 --- a/templates/website/src/payload-types.ts +++ b/templates/website/src/payload-types.ts @@ -108,6 +108,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: { header: Header; footer: Footer; diff --git a/templates/with-cloudflare-d1/.cursor/rules/access-control-advanced.md b/templates/with-cloudflare-d1/.cursor/rules/access-control-advanced.md new file mode 100644 index 00000000000..68f52fd1287 --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/access-control-advanced.md @@ -0,0 +1,519 @@ +--- +title: Access Control - Advanced Patterns +description: Context-aware, time-based, subscription-based access, factory functions, templates +tags: [payload, access-control, security, advanced, performance] +priority: high +--- + +# Advanced Access Control Patterns + +Advanced access control patterns including context-aware access, time-based restrictions, factory functions, and production templates. + +## Context-Aware Access Patterns + +### Locale-Specific Access + +```typescript +import type { Access } from 'payload' + +export const localeSpecificAccess: Access = ({ req: { user, locale } }) => { + // Authenticated users can access all locales + if (user) return true + + // Public users can only access English content + if (locale === 'en') return true + + return false +} +``` + +### Device-Specific Access + +```typescript +export const mobileOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return /mobile|android|iphone/i.test(userAgent) +} + +export const desktopOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return !/mobile|android|iphone/i.test(userAgent) +} +``` + +### IP-Based Access + +```typescript +export const restrictedIpAccess = (allowedIps: string[]): Access => { + return ({ req: { headers } }) => { + const ip = headers?.get('x-forwarded-for') || headers?.get('x-real-ip') + return allowedIps.includes(ip || '') + } +} + +// Usage +const internalIps = ['192.168.1.0/24', '10.0.0.5'] + +export const InternalDocs: CollectionConfig = { + slug: 'internal-docs', + access: { + read: restrictedIpAccess(internalIps), + }, +} +``` + +## Time-Based Access Patterns + +### Today's Records Only + +```typescript +export const todayOnlyAccess: Access = ({ req: { user } }) => { + if (!user) return false + + const now = new Date() + const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000) + + return { + createdAt: { + greater_than_equal: startOfDay.toISOString(), + less_than: endOfDay.toISOString(), + }, + } +} +``` + +### Recent Records (Last N Days) + +```typescript +export const recentRecordsAccess = (days: number): Access => { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - days) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} + +// Usage: Users see only last 30 days, admins see all +export const Logs: CollectionConfig = { + slug: 'logs', + access: { + read: recentRecordsAccess(30), + }, +} +``` + +### Scheduled Content (Publish Date Range) + +```typescript +export const scheduledContentAccess: Access = ({ req: { user } }) => { + // Editors see all content + if (user?.roles?.includes('admin') || user?.roles?.includes('editor')) { + return true + } + + const now = new Date().toISOString() + + // Public sees only content within publish window + return { + and: [ + { publishDate: { less_than_equal: now } }, + { + or: [{ unpublishDate: { exists: false } }, { unpublishDate: { greater_than: now } }], + }, + ], + } +} +``` + +## Subscription-Based Access + +### Active Subscription Required + +```typescript +export const activeSubscriptionAccess: Access = async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + return subscription?.status === 'active' + } catch { + return false + } +} +``` + +### Subscription Tier-Based Access + +```typescript +export const tierBasedAccess = (requiredTier: string): Access => { + const tierHierarchy = ['free', 'basic', 'pro', 'enterprise'] + + return async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + if (subscription?.status !== 'active') return false + + const userTierIndex = tierHierarchy.indexOf(subscription.tier) + const requiredTierIndex = tierHierarchy.indexOf(requiredTier) + + return userTierIndex >= requiredTierIndex + } catch { + return false + } + } +} + +// Usage +export const EnterpriseFeatures: CollectionConfig = { + slug: 'enterprise-features', + access: { + read: tierBasedAccess('enterprise'), + }, +} +``` + +## Factory Functions + +### createRoleBasedAccess + +```typescript +export function createRoleBasedAccess(roles: string[]): Access { + return ({ req: { user } }) => { + if (!user) return false + return roles.some((role) => user.roles?.includes(role)) + } +} + +// Usage +const adminOrEditor = createRoleBasedAccess(['admin', 'editor']) +const moderatorAccess = createRoleBasedAccess(['admin', 'moderator']) +``` + +### createOrgScopedAccess + +```typescript +export function createOrgScopedAccess(allowAdmin = true): Access { + return ({ req: { user } }) => { + if (!user) return false + if (allowAdmin && user.roles?.includes('admin')) return true + + return { + organizationId: { in: user.organizationIds || [] }, + } + } +} + +// Usage +const orgScoped = createOrgScopedAccess() // Admins bypass +const strictOrgScoped = createOrgScopedAccess(false) // Admins also scoped +``` + +### createTeamBasedAccess + +```typescript +export function createTeamBasedAccess(teamField = 'teamId'): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + [teamField]: { in: user.teamIds || [] }, + } + } +} +``` + +### createTimeLimitedAccess + +```typescript +export function createTimeLimitedAccess(daysAccess: number): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - daysAccess) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} +``` + +## Configuration Templates + +### Public + Authenticated Collection + +```typescript +export const PublicAuthCollection: CollectionConfig = { + slug: 'posts', + access: { + // Only admins/editors can create + create: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Authenticated users see all, public sees only published + read: ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } + }, + + // Only admins/editors can update + update: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Only admins can delete + delete: ({ req: { user } }) => { + return user?.roles?.includes('admin') || false + }, + }, + versions: { + drafts: true, + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'content', type: 'richText', required: true }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], +} +``` + +### Self-Service Collection + +```typescript +export const SelfServiceCollection: CollectionConfig = { + slug: 'users', + auth: true, + access: { + // Admins can create users + create: ({ req: { user } }) => user?.roles?.includes('admin') || false, + + // Anyone can read user profiles + read: () => true, + + // Users can update self, admins can update anyone + update: ({ req: { user }, id }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + return user.id === id + }, + + // Only admins can delete + delete: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + fields: [ + { name: 'name', type: 'text', required: true }, + { name: 'email', type: 'email', required: true }, + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + access: { + // Only admins can read/update roles + read: ({ req: { user } }) => user?.roles?.includes('admin') || false, + update: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + }, + ], +} +``` + +## Performance Considerations + +### Avoid Async Operations in Hot Paths + +```typescript +// ❌ Slow: Multiple sequential async calls +export const slowAccess: Access = async ({ req: { user } }) => { + const org = await req.payload.findByID({ collection: 'orgs', id: user.orgId }) + const team = await req.payload.findByID({ collection: 'teams', id: user.teamId }) + const subscription = await req.payload.findByID({ collection: 'subs', id: user.subId }) + + return org.active && team.active && subscription.active +} + +// ✅ Fast: Use query constraints or cache in context +export const fastAccess: Access = ({ req: { user, context } }) => { + // Cache expensive lookups + if (!context.orgStatus) { + context.orgStatus = checkOrgStatus(user.orgId) + } + + return context.orgStatus +} +``` + +### Query Constraint Optimization + +```typescript +// ❌ Avoid: Non-indexed fields in constraints +export const slowQuery: Access = () => ({ + 'metadata.internalCode': { equals: 'ABC123' }, // Slow if not indexed +}) + +// ✅ Better: Use indexed fields +export const fastQuery: Access = () => ({ + status: { equals: 'active' }, // Indexed field + organizationId: { in: ['org1', 'org2'] }, // Indexed field +}) +``` + +### Field Access on Large Arrays + +```typescript +// ❌ Slow: Complex access on array fields +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: async ({ req }) => { + // Async call runs for EVERY array item + const result = await expensiveCheck() + return result + }, + }, + }, + ], +} + +// ✅ Fast: Simple checks or cache result +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: ({ req: { user }, context }) => { + // Cache once, reuse for all items + if (context.canReadSecret === undefined) { + context.canReadSecret = user?.roles?.includes('admin') + } + return context.canReadSecret + }, + }, + }, + ], +} +``` + +### Avoid N+1 Queries + +```typescript +// ❌ N+1 Problem: Query per access check +export const n1Access: Access = async ({ req, id }) => { + // Runs for EACH document in list + const doc = await req.payload.findByID({ collection: 'docs', id }) + return doc.isPublic +} + +// ✅ Better: Use query constraint to filter at DB level +export const efficientAccess: Access = () => { + return { isPublic: { equals: true } } +} +``` + +## Debugging Tips + +### Log Access Check Execution + +```typescript +export const debugAccess: Access = ({ req: { user }, id }) => { + console.log('Access check:', { + userId: user?.id, + userRoles: user?.roles, + docId: id, + timestamp: new Date().toISOString(), + }) + return true +} +``` + +### Verify Arguments Availability + +```typescript +export const checkArgsAccess: Access = (args) => { + console.log('Available arguments:', { + hasReq: 'req' in args, + hasUser: args.req?.user ? 'yes' : 'no', + hasId: args.id ? 'provided' : 'undefined', + hasData: args.data ? 'provided' : 'undefined', + }) + return true +} +``` + +### Test Access Without User + +```typescript +// In test/development +const testAccess = await payload.find({ + collection: 'posts', + overrideAccess: false, // Enforce access control + user: undefined, // Simulate no user +}) + +console.log('Public access result:', testAccess.docs.length) +``` + +## Best Practices + +1. **Default Deny**: Start with restrictive access, gradually add permissions +2. **Type Guards**: Use TypeScript for user type safety +3. **Validate Data**: Never trust frontend-provided IDs or data +4. **Async for Critical Checks**: Use async operations for important security decisions +5. **Consistent Logic**: Apply same rules at field and collection levels +6. **Test Edge Cases**: Test with no user, wrong user, admin user scenarios +7. **Monitor Access**: Log failed access attempts for security review +8. **Regular Audit**: Review access rules quarterly or after major changes +9. **Cache Wisely**: Use `req.context` for expensive operations +10. **Document Intent**: Add comments explaining complex access rules +11. **Avoid Secrets in Client**: Never expose sensitive logic to client-side +12. **Handle Errors Gracefully**: Access functions should return `false` on error, not throw +13. **Test Local API**: Remember to set `overrideAccess: false` when testing +14. **Consider Performance**: Measure impact of async operations +15. **Principle of Least Privilege**: Grant minimum access required + +## Performance Summary + +**Minimize Async Operations**: Use query constraints over async lookups when possible + +**Cache Expensive Checks**: Store results in `req.context` for reuse + +**Index Query Fields**: Ensure fields in query constraints are indexed + +**Avoid Complex Logic in Array Fields**: Simple boolean checks preferred + +**Use Query Constraints**: Let database filter rather than loading all records diff --git a/templates/with-cloudflare-d1/.cursor/rules/access-control.md b/templates/with-cloudflare-d1/.cursor/rules/access-control.md new file mode 100644 index 00000000000..7b9a0a4ba5c --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/access-control.md @@ -0,0 +1,225 @@ +--- +title: Access Control +description: Collection, field, and global access control patterns +tags: [payload, access-control, security, permissions, rbac] +--- + +# Payload CMS Access Control + +## Access Control Layers + +1. **Collection-Level**: Controls operations on entire documents (create, read, update, delete, admin) +2. **Field-Level**: Controls access to individual fields (create, read, update) +3. **Global-Level**: Controls access to global documents (read, update) + +## Collection Access Control + +```typescript +import type { Access } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + // Boolean: Only authenticated users can create + create: ({ req: { user } }) => Boolean(user), + + // Query constraint: Public sees published, users see all + read: ({ req: { user } }) => { + if (user) return true + return { status: { equals: 'published' } } + }, + + // User-specific: Admins or document owner + update: ({ req: { user }, id }) => { + if (user?.roles?.includes('admin')) return true + return { author: { equals: user?.id } } + }, + + // Async: Check related data + delete: async ({ req, id }) => { + const hasComments = await req.payload.count({ + collection: 'comments', + where: { post: { equals: id } }, + }) + return hasComments === 0 + }, + }, +} +``` + +## Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Row-Level Security + +```typescript +// Organization-scoped access +export const organizationScoped: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + + // Users see only their organization's data + return { + organization: { + equals: user?.organization, + }, + } +} + +// Team-based access +export const teamMemberAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + 'team.members': { + contains: user.id, + }, + } +} +``` + +## Field Access Control + +**Field access ONLY returns boolean** (no query constraints). + +```typescript +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +## RBAC Pattern + +Payload does NOT provide a roles system by default. Add a `roles` field to your auth collection: + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Multi-Tenant Access Control + +```typescript +interface User { + id: string + tenantId: string + roles?: string[] +} + +const tenantAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('super-admin')) return true + + return { + tenant: { + equals: (user as User).tenantId, + }, + } +} + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + create: tenantAccess, + read: tenantAccess, + update: tenantAccess, + delete: tenantAccess, + }, + fields: [ + { + name: 'tenant', + type: 'text', + required: true, + access: { + update: ({ req: { user } }) => user?.roles?.includes('super-admin'), + }, + hooks: { + beforeChange: [ + ({ req, operation, value }) => { + if (operation === 'create' && !value) { + return (req.user as User)?.tenantId + } + return value + }, + ], + }, + }, + ], +} +``` + +## Important Notes + +1. **Local API Default**: Access control is **skipped by default** in Local API (`overrideAccess: true`). When passing a `user` parameter, you must set `overrideAccess: false`: + +```typescript +// ❌ WRONG: Passes user but bypasses access control +await payload.find({ + collection: 'posts', + user: someUser, +}) + +// ✅ CORRECT: Respects the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // Required to enforce access control +}) +``` + +2. **Field Access Limitations**: Field-level access does NOT support query constraints - only boolean returns. + +3. **Admin Panel Visibility**: The `admin` access control determines if a collection appears in the admin panel for a user. diff --git a/templates/with-cloudflare-d1/.cursor/rules/adapters.md b/templates/with-cloudflare-d1/.cursor/rules/adapters.md new file mode 100644 index 00000000000..49b8b3367fc --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/adapters.md @@ -0,0 +1,209 @@ +--- +title: Database Adapters & Transactions +description: Database adapters, storage, email, and transaction patterns +tags: [payload, database, mongodb, postgres, sqlite, transactions] +--- + +# Payload CMS Adapters + +## Database Adapters + +### MongoDB + +```typescript +import { mongooseAdapter } from '@payloadcms/db-mongodb' + +export default buildConfig({ + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +### Postgres + +```typescript +import { postgresAdapter } from '@payloadcms/db-postgres' + +export default buildConfig({ + db: postgresAdapter({ + pool: { + connectionString: process.env.DATABASE_URI, + }, + push: false, // Don't auto-push schema changes + migrationDir: './migrations', + }), +}) +``` + +### SQLite + +```typescript +import { sqliteAdapter } from '@payloadcms/db-sqlite' + +export default buildConfig({ + db: sqliteAdapter({ + client: { + url: 'file:./payload.db', + }, + transactionOptions: {}, // Enable transactions (disabled by default) + }), +}) +``` + +## Transactions + +Payload automatically uses transactions for all-or-nothing database operations. + +### Threading req Through Operations + +**CRITICAL**: When performing nested operations in hooks, always pass `req` to maintain transaction context. + +```typescript +// ✅ CORRECT: Thread req through nested operations +const resaveChildren: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + // Find children - pass req + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + req, // Maintains transaction context + }) + + // Update each child - pass req + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + req, // Same transaction as parent operation + }) + } +} + +// ❌ WRONG: Missing req breaks transaction +const brokenHook: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + // Missing req - separate transaction or no transaction + }) + + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + // Missing req - if parent operation fails, these updates persist + }) + } +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +### Manual Transaction Control + +```typescript +const transactionID = await payload.db.beginTransaction() +try { + await payload.create({ + collection: 'orders', + data: orderData, + req: { transactionID }, + }) + await payload.update({ + collection: 'inventory', + id: itemId, + data: { stock: newStock }, + req: { transactionID }, + }) + await payload.db.commitTransaction(transactionID) +} catch (error) { + await payload.db.rollbackTransaction(transactionID) + throw error +} +``` + +## Storage Adapters + +Available storage adapters: + +- **@payloadcms/storage-s3** - AWS S3 +- **@payloadcms/storage-azure** - Azure Blob Storage +- **@payloadcms/storage-gcs** - Google Cloud Storage +- **@payloadcms/storage-r2** - Cloudflare R2 +- **@payloadcms/storage-vercel-blob** - Vercel Blob +- **@payloadcms/storage-uploadthing** - Uploadthing + +### AWS S3 + +```typescript +import { s3Storage } from '@payloadcms/storage-s3' + +export default buildConfig({ + plugins: [ + s3Storage({ + collections: { + media: true, + }, + bucket: process.env.S3_BUCKET, + config: { + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + region: process.env.S3_REGION, + }, + }), + ], +}) +``` + +## Email Adapters + +### Nodemailer (SMTP) + +```typescript +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' + +export default buildConfig({ + email: nodemailerAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + transportOptions: { + host: process.env.SMTP_HOST, + port: 587, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }, + }), +}) +``` + +### Resend + +```typescript +import { resendAdapter } from '@payloadcms/email-resend' + +export default buildConfig({ + email: resendAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + apiKey: process.env.RESEND_API_KEY, + }), +}) +``` + +## Important Notes + +1. **MongoDB Transactions**: Require replica set configuration +2. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +3. **Pass req**: Always pass `req` to nested operations in hooks for transaction safety +4. **Point Fields**: Not supported in SQLite diff --git a/templates/with-cloudflare-d1/.cursor/rules/collections.md b/templates/with-cloudflare-d1/.cursor/rules/collections.md new file mode 100644 index 00000000000..af625108e60 --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/collections.md @@ -0,0 +1,171 @@ +--- +title: Collections +description: Collection configurations and patterns +tags: [payload, collections, auth, upload, drafts] +--- + +# Payload CMS Collections + +## Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +## Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Upload Collection + +```typescript +export const Media: CollectionConfig = { + slug: 'media', + upload: { + staticDir: 'media', + mimeTypes: ['image/*'], + imageSizes: [ + { + name: 'thumbnail', + width: 400, + height: 300, + position: 'centre', + }, + { + name: 'card', + width: 768, + height: 1024, + }, + ], + adminThumbnail: 'thumbnail', + focalPoint: true, + crop: true, + }, + access: { + read: () => true, + }, + fields: [ + { + name: 'alt', + type: 'text', + required: true, + }, + ], +} +``` + +## Versioning & Drafts + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} +``` + +### Draft API Usage + +```typescript +// Create draft +await payload.create({ + collection: 'posts', + data: { title: 'Draft Post' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft version if exists +}) +``` + +## Globals + +Globals are single-instance documents (not collections). + +```typescript +import type { GlobalConfig } from 'payload' + +export const Header: GlobalConfig = { + slug: 'header', + label: 'Header', + admin: { + group: 'Settings', + }, + fields: [ + { + name: 'logo', + type: 'upload', + relationTo: 'media', + required: true, + }, + { + name: 'nav', + type: 'array', + maxRows: 8, + fields: [ + { + name: 'link', + type: 'relationship', + relationTo: 'pages', + }, + { + name: 'label', + type: 'text', + }, + ], + }, + ], +} +``` diff --git a/templates/with-cloudflare-d1/.cursor/rules/components.md b/templates/with-cloudflare-d1/.cursor/rules/components.md new file mode 100644 index 00000000000..8610b8d7b33 --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/components.md @@ -0,0 +1,794 @@ +# Custom Components in Payload CMS + +Custom Components allow you to fully customize the Admin Panel by swapping in your own React components. You can replace nearly every part of the interface or add entirely new functionality. + +## Component Types + +There are four main types of Custom Components: + +1. **Root Components** - Affect the Admin Panel globally (logo, nav, header) +2. **Collection Components** - Specific to collection views +3. **Global Components** - Specific to global document views +4. **Field Components** - Custom field UI and cells + +## Defining Custom Components + +### Component Paths + +Components are defined using file paths (not direct imports) to keep the config lightweight and Node.js compatible. + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + logout: { + Button: '/src/components/Logout#MyComponent', // Named export + }, + Nav: '/src/components/Nav', // Default export + }, + }, +}) +``` + +**Component Path Rules:** + +1. Paths are relative to project root (or `config.admin.importMap.baseDir`) +2. For **named exports**: append `#ExportName` or use `exportName` property +3. For **default exports**: no suffix needed +4. File extensions can be omitted + +### Component Config Object + +Instead of a string path, you can pass a config object: + +```typescript +{ + logout: { + Button: { + path: '/src/components/Logout', + exportName: 'MyComponent', + clientProps: { customProp: 'value' }, + serverProps: { asyncData: someData }, + }, + }, +} +``` + +**Config Properties:** + +| Property | Description | +| ------------- | ----------------------------------------------------- | +| `path` | File path to component (named exports via `#`) | +| `exportName` | Named export (alternative to `#` in path) | +| `clientProps` | Props for Client Components (must be serializable) | +| `serverProps` | Props for Server Components (can be non-serializable) | + +### Setting Base Directory + +```typescript +import path from 'path' +import { fileURLToPath } from 'node:url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), // Set base directory + }, + components: { + Nav: '/components/Nav', // Now relative to src/ + }, + }, +}) +``` + +## Server vs Client Components + +**All components are React Server Components by default.** + +### Server Components (Default) + +Can use Local API directly, perform async operations, and access full Payload instance. + +```tsx +import React from 'react' +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const page = await payload.findByID({ + collection: 'pages', + id: '123', + }) + + return

{page.title}

+} + +export default MyServerComponent +``` + +### Client Components + +Use the `'use client'` directive for interactivity, hooks, state, etc. + +```tsx +'use client' +import React, { useState } from 'react' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + + return +} +``` + +**Important:** Client Components cannot receive non-serializable props (functions, class instances, etc.). Payload automatically strips these when passing to client components. + +## Default Props + +All Custom Components receive these props by default: + +| Prop | Description | Type | +| --------- | ---------------------------------------- | --------- | +| `payload` | Payload instance (Local API access) | `Payload` | +| `i18n` | Internationalization object | `I18n` | +| `locale` | Current locale (if localization enabled) | `string` | + +**Server Component Example:** + +```tsx +async function MyComponent({ payload, i18n, locale }) { + const data = await payload.find({ + collection: 'posts', + locale, + }) + + return
{data.docs.length} posts
+} +``` + +**Client Component Example:** + +```tsx +'use client' +import { usePayload, useLocale, useTranslation } from '@payloadcms/ui' + +export function MyComponent() { + // Access via hooks in client components + const { getLocal, getByID } = usePayload() + const locale = useLocale() + const { t, i18n } = useTranslation() + + return
{t('myKey')}
+} +``` + +## Custom Props + +Pass additional props using `clientProps` or `serverProps`: + +```typescript +{ + logout: { + Button: { + path: '/components/Logout', + clientProps: { + buttonText: 'Sign Out', + onLogout: () => console.log('Logged out'), + }, + }, + }, +} +``` + +Receive in component: + +```tsx +'use client' +export function Logout({ buttonText, onLogout }) { + return +} +``` + +## Root Components + +Root Components affect the entire Admin Panel. + +### Available Root Components + +| Component | Description | Config Path | +| ----------------- | -------------------------------- | ---------------------------------- | +| `Nav` | Entire navigation sidebar | `admin.components.Nav` | +| `graphics.Icon` | Small icon (used in nav) | `admin.components.graphics.Icon` | +| `graphics.Logo` | Full logo (used on login) | `admin.components.graphics.Logo` | +| `logout.Button` | Logout button | `admin.components.logout.Button` | +| `actions` | Header actions (array) | `admin.components.actions` | +| `header` | Above header (array) | `admin.components.header` | +| `beforeDashboard` | Before dashboard content (array) | `admin.components.beforeDashboard` | +| `afterDashboard` | After dashboard content (array) | `admin.components.afterDashboard` | +| `beforeLogin` | Before login form (array) | `admin.components.beforeLogin` | +| `afterLogin` | After login form (array) | `admin.components.afterLogin` | +| `beforeNavLinks` | Before nav links (array) | `admin.components.beforeNavLinks` | +| `afterNavLinks` | After nav links (array) | `admin.components.afterNavLinks` | +| `settingsMenu` | Settings menu items (array) | `admin.components.settingsMenu` | +| `providers` | Custom React Context providers | `admin.components.providers` | +| `views` | Custom views (dashboard, etc.) | `admin.components.views` | + +### Example: Custom Logo + +```typescript +export default buildConfig({ + admin: { + components: { + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + }, + }, +}) +``` + +```tsx +// components/Logo.tsx +export default function Logo() { + return My Brand +} +``` + +### Example: Header Actions + +```typescript +export default buildConfig({ + admin: { + components: { + actions: ['/components/ClearCacheButton', '/components/PreviewButton'], + }, + }, +}) +``` + +```tsx +// components/ClearCacheButton.tsx +'use client' +export default function ClearCacheButton() { + return ( + + ) +} +``` + +## Collection Components + +Collection Components are specific to a collection's views. + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view components + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/CustomSaveDraft', + PublishButton: '/components/CustomPublish', + }, + + // List view components + list: { + Header: '/components/PostsListHeader', + beforeList: ['/components/ListFilters'], + afterList: ['/components/ListFooter'], + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Global Components + +Similar to Collection Components but for Global documents. + +```typescript +import type { GlobalConfig } from 'payload' + +export const Settings: GlobalConfig = { + slug: 'settings', + admin: { + components: { + edit: { + PreviewButton: '/components/SettingsPreview', + SaveButton: '/components/SettingsSave', + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Field Components + +Customize how fields render in Edit and List views. + +### Field Component (Edit View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Field: '/components/StatusField', + }, + }, +} +``` + +```tsx +// components/StatusField.tsx +'use client' +import { useField } from '@payloadcms/ui' +import type { SelectFieldClientComponent } from 'payload' + +export const StatusField: SelectFieldClientComponent = ({ path, field }) => { + const { value, setValue } = useField({ path }) + + return ( +
+ + +
+ ) +} +``` + +### Cell Component (List View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Cell: '/components/StatusCell', + }, + }, +} +``` + +```tsx +// components/StatusCell.tsx +import type { SelectFieldCellComponent } from 'payload' + +export const StatusCell: SelectFieldCellComponent = ({ data, cellData }) => { + const isPublished = cellData === 'published' + + return ( + + {cellData} + + ) +} +``` + +### UI Field (Presentational Only) + +Special field type for adding custom UI without affecting data: + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +```tsx +// components/RefundButton.tsx +'use client' +import { useDocumentInfo } from '@payloadcms/ui' + +export default function RefundButton() { + const { id } = useDocumentInfo() + + return ( + + ) +} +``` + +## Using Hooks + +Payload provides many React hooks for Client Components: + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Current document info (id, slug, etc.) + useField, // Field value and setValue + useForm, // Form state and dispatch + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +**Important:** These hooks only work in Client Components within the Admin Panel context. + +## Accessing Payload Config + +**In Server Components:** + +```tsx +async function MyServerComponent({ payload }) { + const { config } = payload + return
{config.serverURL}
+} +``` + +**In Client Components:** + +```tsx +'use client' +import { useConfig } from '@payloadcms/ui' + +export function MyClientComponent() { + const { config } = useConfig() // Client-safe config + return
{config.serverURL}
+} +``` + +**Important:** Client Components receive a serializable version of the config (functions, validation, etc. are stripped). + +## Field Config Access + +**Server Component:** + +```tsx +import type { TextFieldServerComponent } from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = ({ field }) => { + return
Field name: {field.name}
+} +``` + +**Client Component:** + +```tsx +'use client' +import type { TextFieldClientComponent } from 'payload' + +export const MyFieldComponent: TextFieldClientComponent = ({ clientField }) => { + // clientField has non-serializable props removed + return
Field name: {clientField.name}
+} +``` + +## Translations (i18n) + +**Server Component:** + +```tsx +import { getTranslation } from '@payloadcms/translations' + +async function MyServerComponent({ i18n }) { + const translatedTitle = getTranslation(myTranslation, i18n) + return

{translatedTitle}

+} +``` + +**Client Component:** + +```tsx +'use client' +import { useTranslation } from '@payloadcms/ui' + +export function MyClientComponent() { + const { t, i18n } = useTranslation() + + return ( +
+

{t('namespace:key', { variable: 'value' })}

+

Language: {i18n.language}

+
+ ) +} +``` + +## Styling Components + +### Using CSS Variables + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Custom Component
+} +``` + +```scss +// styles.scss +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} +``` + +### Importing Payload SCSS + +```scss +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +## Common Patterns + +### Conditional Field Visibility + +```tsx +'use client' +import { useFormFields } from '@payloadcms/ui' +import type { TextFieldClientComponent } from 'payload' + +export const ConditionalField: TextFieldClientComponent = ({ path }) => { + const showField = useFormFields(([fields]) => fields.enableFeature?.value) + + if (!showField) return null + + return +} +``` + +### Loading Data from API + +```tsx +'use client' +import { useState, useEffect } from 'react' + +export function DataLoader() { + const [data, setData] = useState(null) + + useEffect(() => { + fetch('/api/custom-data') + .then((res) => res.json()) + .then(setData) + }, []) + + return
{JSON.stringify(data)}
+} +``` + +### Using Local API in Server Components + +```tsx +import type { Payload } from 'payload' + +async function RelatedPosts({ payload, id }: { payload: Payload; id: string }) { + const post = await payload.findByID({ + collection: 'posts', + id, + depth: 0, + }) + + const related = await payload.find({ + collection: 'posts', + where: { + category: { equals: post.category }, + id: { not_equals: id }, + }, + limit: 5, + }) + + return ( +
+

Related Posts

+
    + {related.docs.map((doc) => ( +
  • {doc.title}
  • + ))} +
+
+ ) +} + +export default RelatedPosts +``` + +## Performance Best Practices + +### 1. Minimize Client Bundle Size + +```tsx +// ❌ BAD: Imports entire package +'use client' +import { Button } from '@payloadcms/ui' + +// ✅ GOOD: Tree-shakeable import for frontend +import { Button } from '@payloadcms/ui/elements/Button' +``` + +**Rule:** In Admin Panel UI, import from `@payloadcms/ui`. In frontend code, use specific paths. + +### 2. Optimize Re-renders + +```tsx +// ❌ BAD: Re-renders on every form change +'use client' +import { useForm } from '@payloadcms/ui' + +export function MyComponent() { + const { fields } = useForm() + // Re-renders on ANY field change +} + +// ✅ GOOD: Only re-renders when specific field changes +;('use client') +import { useFormFields } from '@payloadcms/ui' + +export function MyComponent({ path }) { + const value = useFormFields(([fields]) => fields[path]) + // Only re-renders when this field changes +} +``` + +### 3. Use Server Components When Possible + +```tsx +// ✅ GOOD: No JavaScript sent to client +async function PostCount({ payload }) { + const { totalDocs } = await payload.find({ + collection: 'posts', + limit: 0, + }) + + return

{totalDocs} posts

+} + +// Only use client components when you need: +// - State (useState, useReducer) +// - Effects (useEffect) +// - Event handlers (onClick, onChange) +// - Browser APIs (localStorage, window) +``` + +### 4. React Best Practices + +- Use React.memo() for expensive components +- Implement proper key props in lists +- Avoid inline function definitions in renders +- Use Suspense boundaries for async operations + +## Import Map + +Payload generates an import map at `app/(payload)/admin/importMap.js` that resolves all component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Override location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Type Safety + +Use Payload's TypeScript types for components: + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, +} from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = (props) => { + // Fully typed props +} +``` + +## Troubleshooting + +### "useConfig is undefined" or similar hook errors + +**Cause:** Dependency version mismatch between Payload packages. + +**Solution:** Pin all `@payloadcms/*` packages to the exact same version: + +```json +{ + "dependencies": { + "payload": "3.0.0", + "@payloadcms/ui": "3.0.0", + "@payloadcms/richtext-lexical": "3.0.0" + } +} +``` + +### Component not loading + +1. Check file path is correct (relative to baseDir) +2. Verify named export syntax: `/path/to/file#ExportName` +3. Run `payload generate:importmap` to regenerate +4. Check for TypeScript errors in component file + +## Resources + +- [Custom Components Docs](https://payloadcms.com/docs/custom-components/overview) +- [Root Components](https://payloadcms.com/docs/custom-components/root-components) +- [Custom Views](https://payloadcms.com/docs/custom-components/custom-views) +- [React Hooks](https://payloadcms.com/docs/admin/react-hooks) +- [Custom CSS](https://payloadcms.com/docs/admin/customizing-css) diff --git a/templates/with-cloudflare-d1/.cursor/rules/endpoints.md b/templates/with-cloudflare-d1/.cursor/rules/endpoints.md new file mode 100644 index 00000000000..8a2481dbe5d --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/endpoints.md @@ -0,0 +1,236 @@ +--- +title: Custom Endpoints +description: Custom REST API endpoints with authentication and helpers +tags: [payload, endpoints, api, routes, webhooks] +--- + +# Payload Custom Endpoints + +## Basic Endpoint Pattern + +Custom endpoints are **not authenticated by default**. Always check `req.user`. + +```typescript +import { APIError } from 'payload' +import type { Endpoint } from 'payload' + +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} +``` + +## Route Parameters + +```typescript +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Request Body Handling + +```typescript +// Manual JSON parsing +export const createEndpoint: Endpoint = { + path: '/create', + method: 'post', + handler: async (req) => { + const data = await req.json() + + const result = await req.payload.create({ + collection: 'posts', + data, + }) + + return Response.json(result) + }, +} + +// Using helper (handles JSON + files) +import { addDataAndFileToRequest } from 'payload' + +export const uploadEndpoint: Endpoint = { + path: '/upload', + method: 'post', + handler: async (req) => { + await addDataAndFileToRequest(req) + + // req.data contains parsed body + // req.file contains uploaded file (if multipart) + + const result = await req.payload.create({ + collection: 'media', + data: req.data, + file: req.file, + }) + + return Response.json(result) + }, +} +``` + +## Query Parameters + +```typescript +export const searchEndpoint: Endpoint = { + path: '/search', + method: 'get', + handler: async (req) => { + const url = new URL(req.url) + const query = url.searchParams.get('q') + const limit = parseInt(url.searchParams.get('limit') || '10') + + const results = await req.payload.find({ + collection: 'posts', + where: { + title: { + contains: query, + }, + }, + limit, + }) + + return Response.json(results) + }, +} +``` + +## CORS Headers + +```typescript +import { headersWithCors } from 'payload' + +export const corsEndpoint: Endpoint = { + path: '/public-data', + method: 'get', + handler: async (req) => { + const data = await fetchPublicData() + + return Response.json(data, { + headers: headersWithCors({ + headers: new Headers(), + req, + }), + }) + }, +} +``` + +## Error Handling + +```typescript +import { APIError } from 'payload' + +export const validateEndpoint: Endpoint = { + path: '/validate', + method: 'post', + handler: async (req) => { + const data = await req.json() + + if (!data.email) { + throw new APIError('Email is required', 400) + } + + return Response.json({ valid: true }) + }, +} +``` + +## Endpoint Placement + +### Collection Endpoints + +Mounted at `/api/{collection-slug}/{path}`. + +```typescript +export const Orders: CollectionConfig = { + slug: 'orders', + endpoints: [ + { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + // Available at: /api/orders/:id/tracking + const orderId = req.routeParams.id + return Response.json({ orderId }) + }, + }, + ], +} +``` + +### Global Endpoints + +Mounted at `/api/globals/{global-slug}/{path}`. + +```typescript +export const Settings: GlobalConfig = { + slug: 'settings', + endpoints: [ + { + path: '/clear-cache', + method: 'post', + handler: async (req) => { + // Available at: /api/globals/settings/clear-cache + await clearCache() + return Response.json({ message: 'Cache cleared' }) + }, + }, + ], +} +``` + +### Root Endpoints + +Mounted at `/api/{path}`. + +```typescript +export default buildConfig({ + endpoints: [ + { + path: '/hello', + method: 'get', + handler: () => { + // Available at: /api/hello + return Response.json({ message: 'Hello!' }) + }, + }, + ], +}) +``` + +## Best Practices + +1. **Always check authentication** - Custom endpoints are not authenticated by default +2. **Use `req.payload` for operations** - Ensures access control and hooks execute +3. **Use helpers for common tasks** - `addDataAndFileToRequest`, `headersWithCors` +4. **Throw `APIError` for errors** - Provides consistent error responses +5. **Return Web API `Response`** - Use `Response.json()` for consistent responses +6. **Validate input** - Check required fields, validate types +7. **Log errors** - Use `req.payload.logger` for debugging diff --git a/templates/with-cloudflare-d1/.cursor/rules/field-type-guards.md b/templates/with-cloudflare-d1/.cursor/rules/field-type-guards.md new file mode 100644 index 00000000000..3514ad44993 --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/field-type-guards.md @@ -0,0 +1,230 @@ +--- +title: Field Type Guards +description: Runtime field type checking and safe type narrowing +tags: [payload, typescript, type-guards, fields] +--- + +# Payload Field Type Guards + +Type guards for runtime field type checking and safe type narrowing. + +## Most Common Guards + +### fieldAffectsData + +**Most commonly used guard.** Checks if field stores data (has name and is not UI-only). + +```typescript +import { fieldAffectsData } from 'payload' + +function generateSchema(fields: Field[]) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + // Safe to access field.name + schema[field.name] = getFieldType(field) + } + }) +} + +// Filter data fields +const dataFields = fields.filter(fieldAffectsData) +``` + +### fieldHasSubFields + +Checks if field contains nested fields (group, array, row, or collapsible). + +```typescript +import { fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[]): void { + fields.forEach((field) => { + if (fieldHasSubFields(field)) { + // Safe to access field.fields + traverseFields(field.fields) + } + }) +} +``` + +### fieldIsArrayType + +Checks if field type is `'array'`. + +```typescript +import { fieldIsArrayType } from 'payload' + +if (fieldIsArrayType(field)) { + // field.type === 'array' + console.log(`Min rows: ${field.minRows}`) + console.log(`Max rows: ${field.maxRows}`) +} +``` + +## Capability Guards + +### fieldSupportsMany + +Checks if field can have multiple values (select, relationship, or upload with `hasMany`). + +```typescript +import { fieldSupportsMany } from 'payload' + +if (fieldSupportsMany(field)) { + // field.type is 'select' | 'relationship' | 'upload' + if (field.hasMany) { + console.log('Field accepts multiple values') + } +} +``` + +### fieldHasMaxDepth + +Checks if field is relationship/upload/join with numeric `maxDepth` property. + +```typescript +import { fieldHasMaxDepth } from 'payload' + +if (fieldHasMaxDepth(field)) { + // field.type is 'upload' | 'relationship' | 'join' + // AND field.maxDepth is number + const remainingDepth = field.maxDepth - currentDepth +} +``` + +### fieldIsVirtual + +Checks if field is virtual (computed or virtual relationship). + +```typescript +import { fieldIsVirtual } from 'payload' + +if (fieldIsVirtual(field)) { + // field.virtual is truthy + if (typeof field.virtual === 'string') { + console.log(`Virtual path: ${field.virtual}`) + } +} +``` + +## Type Checking Guards + +### fieldIsBlockType + +```typescript +import { fieldIsBlockType } from 'payload' + +if (fieldIsBlockType(field)) { + // field.type === 'blocks' + field.blocks.forEach((block) => { + console.log(`Block: ${block.slug}`) + }) +} +``` + +### fieldIsGroupType + +```typescript +import { fieldIsGroupType } from 'payload' + +if (fieldIsGroupType(field)) { + // field.type === 'group' + console.log(`Interface: ${field.interfaceName}`) +} +``` + +### fieldIsPresentationalOnly + +```typescript +import { fieldIsPresentationalOnly } from 'payload' + +if (fieldIsPresentationalOnly(field)) { + // field.type === 'ui' + // Skip in data operations, GraphQL schema, etc. + return +} +``` + +## Common Patterns + +### Recursive Field Traversal + +```typescript +import { fieldAffectsData, fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[], callback: (field: Field) => void) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + callback(field) + } + + if (fieldHasSubFields(field)) { + traverseFields(field.fields, callback) + } + }) +} +``` + +### Filter Data-Bearing Fields + +```typescript +import { fieldAffectsData, fieldIsPresentationalOnly, fieldIsHiddenOrDisabled } from 'payload' + +const dataFields = fields.filter( + (field) => + fieldAffectsData(field) && !fieldIsPresentationalOnly(field) && !fieldIsHiddenOrDisabled(field), +) +``` + +### Container Type Switching + +```typescript +import { fieldIsArrayType, fieldIsBlockType, fieldHasSubFields } from 'payload' + +if (fieldIsArrayType(field)) { + // Handle array-specific logic +} else if (fieldIsBlockType(field)) { + // Handle blocks-specific logic +} else if (fieldHasSubFields(field)) { + // Handle group/row/collapsible +} +``` + +### Safe Property Access + +```typescript +import { fieldSupportsMany, fieldHasMaxDepth } from 'payload' + +// With guard - safe access +if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') +} + +if (fieldHasMaxDepth(field)) { + const depth = field.maxDepth // TypeScript knows this is number +} +``` + +## All Available Guards + +| Type Guard | Checks For | Use When | +| --------------------------- | --------------------------------- | ---------------------------------------- | +| `fieldAffectsData` | Field stores data (has name) | Need to access field data or name | +| `fieldHasSubFields` | Field contains nested fields | Recursively traverse fields | +| `fieldIsArrayType` | Field is array type | Distinguish arrays from other containers | +| `fieldIsBlockType` | Field is blocks type | Handle blocks-specific logic | +| `fieldIsGroupType` | Field is group type | Handle group-specific logic | +| `fieldSupportsMany` | Field can have multiple values | Check for `hasMany` support | +| `fieldHasMaxDepth` | Field supports depth control | Control relationship/upload/join depth | +| `fieldIsPresentationalOnly` | Field is UI-only | Exclude from data operations | +| `fieldIsSidebar` | Field positioned in sidebar | Separate sidebar rendering | +| `fieldIsID` | Field name is 'id' | Special ID field handling | +| `fieldIsHiddenOrDisabled` | Field is hidden or disabled | Filter from UI operations | +| `fieldShouldBeLocalized` | Field needs localization | Proper locale table checks | +| `fieldIsVirtual` | Field is virtual | Skip in database transforms | +| `tabHasName` | Tab is named (stores data) | Distinguish named vs unnamed tabs | +| `groupHasName` | Group is named (stores data) | Distinguish named vs unnamed groups | +| `optionIsObject` | Option is `{label, value}` | Access option properties safely | +| `optionsAreObjects` | All options are objects | Batch option processing | +| `optionIsValue` | Option is string value | Handle string options | +| `valueIsValueWithRelation` | Value is polymorphic relationship | Handle polymorphic relationships | diff --git a/templates/with-cloudflare-d1/.cursor/rules/fields.md b/templates/with-cloudflare-d1/.cursor/rules/fields.md new file mode 100644 index 00000000000..8468e41f599 --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/fields.md @@ -0,0 +1,317 @@ +--- +title: Fields +description: Field types, patterns, and configurations +tags: [payload, fields, validation, conditional] +--- + +# Payload CMS Fields + +## Common Field Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## Field Types + +### Text Field + +```typescript +{ + name: 'title', + type: 'text', + required: true, + unique: true, + minLength: 5, + maxLength: 100, + index: true, + localized: true, + defaultValue: 'Default Title', + validate: (value) => Boolean(value) || 'Required', + admin: { + placeholder: 'Enter title...', + position: 'sidebar', + condition: (data) => data.showTitle === true, + }, +} +``` + +### Rich Text (Lexical) + +```typescript +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { HeadingFeature, LinkFeature } from '@payloadcms/richtext-lexical' + +{ + name: 'content', + type: 'richText', + required: true, + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + HeadingFeature({ + enabledHeadingSizes: ['h1', 'h2', 'h3'], + }), + LinkFeature({ + enabledCollections: ['posts', 'pages'], + }), + ], + }), +} +``` + +### Relationship + +```typescript +// Single relationship +{ + name: 'author', + type: 'relationship', + relationTo: 'users', + required: true, + maxDepth: 2, +} + +// Multiple relationships (hasMany) +{ + name: 'categories', + type: 'relationship', + relationTo: 'categories', + hasMany: true, + filterOptions: { + active: { equals: true }, + }, +} + +// Polymorphic relationship +{ + name: 'relatedContent', + type: 'relationship', + relationTo: ['posts', 'pages'], + hasMany: true, +} +``` + +### Array + +```typescript +{ + name: 'slides', + type: 'array', + minRows: 2, + maxRows: 10, + labels: { + singular: 'Slide', + plural: 'Slides', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'image', + type: 'upload', + relationTo: 'media', + }, + ], + admin: { + initCollapsed: true, + }, +} +``` + +### Blocks + +```typescript +import type { Block } from 'payload' + +const HeroBlock: Block = { + slug: 'hero', + interfaceName: 'HeroBlock', + fields: [ + { + name: 'heading', + type: 'text', + required: true, + }, + { + name: 'background', + type: 'upload', + relationTo: 'media', + }, + ], +} + +const ContentBlock: Block = { + slug: 'content', + fields: [ + { + name: 'text', + type: 'richText', + }, + ], +} + +{ + name: 'layout', + type: 'blocks', + blocks: [HeroBlock, ContentBlock], +} +``` + +### Select + +```typescript +{ + name: 'status', + type: 'select', + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + ], + defaultValue: 'draft', + required: true, +} + +// Multiple select +{ + name: 'tags', + type: 'select', + hasMany: true, + options: ['tech', 'news', 'sports'], +} +``` + +### Upload + +```typescript +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + required: true, + filterOptions: { + mimeType: { contains: 'image' }, + }, +} +``` + +### Point (Geolocation) + +```typescript +{ + name: 'location', + type: 'point', + label: 'Location', + required: true, +} + +// Query by distance +const nearbyLocations = await payload.find({ + collection: 'stores', + where: { + location: { + near: [10, 20], // [longitude, latitude] + maxDistance: 5000, // in meters + minDistance: 1000, + }, + }, +}) +``` + +### Join Fields (Reverse Relationships) + +```typescript +// From Users collection - show user's orders +{ + name: 'orders', + type: 'join', + collection: 'orders', + on: 'customer', // The field in 'orders' that references this user +} +``` + +### Tabs & Groups + +```typescript +// Tabs +{ + type: 'tabs', + tabs: [ + { + label: 'Content', + fields: [ + { name: 'title', type: 'text' }, + { name: 'body', type: 'richText' }, + ], + }, + { + label: 'SEO', + fields: [ + { name: 'metaTitle', type: 'text' }, + { name: 'metaDescription', type: 'textarea' }, + ], + }, + ], +} + +// Group (named) +{ + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], +} +``` + +## Validation + +```typescript +{ + name: 'email', + type: 'email', + validate: (value, { operation, data, siblingData }) => { + if (operation === 'create' && !value) { + return 'Email is required' + } + if (value && !value.includes('@')) { + return 'Invalid email format' + } + return true + }, +} +``` diff --git a/templates/with-cloudflare-d1/.cursor/rules/hooks.md b/templates/with-cloudflare-d1/.cursor/rules/hooks.md new file mode 100644 index 00000000000..1f168f9eaeb --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/hooks.md @@ -0,0 +1,175 @@ +--- +title: Hooks +description: Collection hooks, field hooks, and context patterns +tags: [payload, hooks, lifecycle, context] +--- + +# Payload CMS Hooks + +## Collection Hooks + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Field Hooks + +```typescript +import type { FieldHook } from 'payload' + +const beforeValidateHook: FieldHook = ({ value }) => { + return value.trim().toLowerCase() +} + +const afterReadHook: FieldHook = ({ value, req }) => { + // Hide email from non-admins + if (!req.user?.roles?.includes('admin')) { + return value.replace(/(.{2})(.*)(@.*)/, '$1***$3') + } + return value +} + +{ + name: 'email', + type: 'email', + hooks: { + beforeValidate: [beforeValidateHook], + afterRead: [afterReadHook], + }, +} +``` + +## Hook Context + +Share data between hooks or control hook behavior using request context: + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + beforeChange: [ + async ({ context }) => { + context.expensiveData = await fetchExpensiveData() + }, + ], + afterChange: [ + async ({ context, doc }) => { + // Reuse from previous hook + await processData(doc, context.expensiveData) + }, + ], + }, +} +``` + +## Next.js Revalidation Pattern + +```typescript +import type { CollectionAfterChangeHook } from 'payload' +import { revalidatePath } from 'next/cache' + +export const revalidatePage: CollectionAfterChangeHook = ({ + doc, + previousDoc, + req: { payload, context }, +}) => { + if (!context.disableRevalidate) { + if (doc._status === 'published') { + const path = doc.slug === 'home' ? '/' : `/${doc.slug}` + payload.logger.info(`Revalidating page at path: ${path}`) + revalidatePath(path) + } + + // Revalidate old path if unpublished + if (previousDoc?._status === 'published' && doc._status !== 'published') { + const oldPath = previousDoc.slug === 'home' ? '/' : `/${previousDoc.slug}` + revalidatePath(oldPath) + } + } + return doc +} +``` + +## Date Field Auto-Set + +```typescript +{ + name: 'publishedOn', + type: 'date', + hooks: { + beforeChange: [ + ({ siblingData, value }) => { + if (siblingData._status === 'published' && !value) { + return new Date() + } + return value + }, + ], + }, +} +``` + +## Best Practices + +- Use `beforeValidate` for data formatting +- Use `beforeChange` for business logic +- Use `afterChange` for side effects +- Use `afterRead` for computed fields +- Store expensive operations in `context` +- Pass `req` to nested operations for transaction safety +- Use context flags to prevent infinite loops diff --git a/templates/with-cloudflare-d1/.cursor/rules/payload-overview.md b/templates/with-cloudflare-d1/.cursor/rules/payload-overview.md new file mode 100644 index 00000000000..290c47822ab --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/payload-overview.md @@ -0,0 +1,126 @@ +--- +title: Payload CMS Overview +description: Core principles and quick reference for Payload CMS development +tags: [payload, overview, quickstart] +--- + +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Quick Reference + +| Task | Solution | +| --------------------- | ---------------------------------- | +| Auto-generate slugs | `slugField()` | +| Restrict by user | Access control with query | +| Local API user ops | `user` + `overrideAccess: false` | +| Draft/publish | `versions: { drafts: true }` | +| Computed fields | `virtual: true` with afterRead | +| Conditional fields | `admin.condition` | +| Custom validation | `validate` function | +| Filter relationships | `filterOptions` on field | +| Select fields | `select` parameter | +| Auto-set dates | beforeChange hook | +| Prevent loops | `req.context` check | +| Cascading deletes | beforeDelete hook | +| Geospatial queries | `point` field with `near`/`within` | +| Reverse relationships | `join` field type | +| Query relationships | Nested property syntax | +| Complex queries | AND/OR logic | +| Transactions | Pass `req` to operations | +| Background jobs | Jobs queue with tasks | +| Custom routes | Collection custom endpoints | +| Cloud storage | Storage adapter plugins | +| Multi-language | `localization` + `localized: true` | + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/with-cloudflare-d1/.cursor/rules/plugin-development.md b/templates/with-cloudflare-d1/.cursor/rules/plugin-development.md new file mode 100644 index 00000000000..d92bb12fb40 --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/plugin-development.md @@ -0,0 +1,323 @@ +--- +title: Plugin Development +description: Creating Payload CMS plugins with TypeScript patterns +tags: [payload, plugins, architecture, patterns] +--- + +# Payload Plugin Development + +## Plugin Architecture + +Plugins are functions that receive configuration options and return a function that transforms the Payload config: + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + enabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + // Transform config here + }) +``` + +**Key Pattern:** Double arrow function (currying) + +- First function: Accepts plugin options, returns plugin function +- Second function: Accepts Payload config, returns modified config + +## Adding Fields to Collections + +```typescript +export const seoPlugin = + (options: { collections?: string[] }): Plugin => + (config: Config): Config => { + const seoFields: Field[] = [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], + }, + ] + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...seoFields], + } + } + return collection + }), + } + } +``` + +## Adding New Collections + +```typescript +export const redirectsPlugin = + (options: { overrides?: Partial }): Plugin => + (config: Config): Config => { + const redirectsCollection: CollectionConfig = { + slug: 'redirects', + access: { read: () => true }, + fields: [ + { name: 'from', type: 'text', required: true, unique: true }, + { name: 'to', type: 'text', required: true }, + ], + ...options.overrides, + } + + return { + ...config, + collections: [...(config.collections || []), redirectsCollection], + } + } +``` + +## Adding Hooks + +```typescript +const resaveChildrenHook: CollectionAfterChangeHook = async ({ doc, req, operation }) => { + if (operation === 'update') { + const children = await req.payload.find({ + collection: 'pages', + where: { parent: { equals: doc.id } }, + }) + + for (const child of children.docs) { + await req.payload.update({ + collection: 'pages', + id: child.id, + data: child, + }) + } + } + return doc +} + +export const nestedDocsPlugin = + (options: { collections: string[] }): Plugin => + (config: Config): Config => ({ + ...config, + collections: (config.collections || []).map((collection) => { + if (options.collections.includes(collection.slug)) { + return { + ...collection, + hooks: { + ...(collection.hooks || {}), + afterChange: [resaveChildrenHook, ...(collection.hooks?.afterChange || [])], + }, + } + } + return collection + }), + }) +``` + +## Adding Root-Level Endpoints + +```typescript +export const seoPlugin = + (options: { generateTitle?: (doc: any) => string }): Plugin => + (config: Config): Config => { + const generateTitleEndpoint: Endpoint = { + path: '/plugin-seo/generate-title', + method: 'post', + handler: async (req) => { + const data = await req.json?.() + const result = options.generateTitle ? options.generateTitle(data.doc) : '' + return Response.json({ result }) + }, + } + + return { + ...config, + endpoints: [...(config.endpoints ?? []), generateTitleEndpoint], + } + } +``` + +## Field Overrides with Defaults + +```typescript +type FieldsOverride = (args: { defaultFields: Field[] }) => Field[] + +interface PluginConfig { + collections?: string[] + fields?: FieldsOverride +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const defaultFields: Field[] = [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ] + + const fields = + options.fields && typeof options.fields === 'function' + ? options.fields({ defaultFields }) + : defaultFields + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...fields], + } + } + return collection + }), + } + } +``` + +## Disable Plugin Pattern + +```typescript +interface PluginConfig { + disabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + // Always add collections/fields for database schema consistency + if (!config.collections) { + config.collections = [] + } + + config.collections.push({ + slug: 'plugin-collection', + fields: [{ name: 'title', type: 'text' }], + }) + + // If disabled, return early but keep schema changes + if (options.disabled) { + return config + } + + // Add endpoints, hooks, components only when enabled + config.endpoints = [ + ...(config.endpoints ?? []), + { + path: '/my-endpoint', + method: 'get', + handler: async () => Response.json({ message: 'Hello' }), + }, + ] + + return config + } +``` + +## Admin Components + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + if (!config.admin) config.admin = {} + if (!config.admin.components) config.admin.components = {} + if (!config.admin.components.beforeDashboard) { + config.admin.components.beforeDashboard = [] + } + + // Add client component + config.admin.components.beforeDashboard.push('my-plugin-name/client#BeforeDashboardClient') + + // Add server component (RSC) + config.admin.components.beforeDashboard.push('my-plugin-name/rsc#BeforeDashboardServer') + + return config + } +``` + +## onInit Hook + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const incomingOnInit = config.onInit + + config.onInit = async (payload) => { + // IMPORTANT: Call existing onInit first + if (incomingOnInit) await incomingOnInit(payload) + + // Plugin initialization + payload.logger.info('Plugin initialized') + + // Example: Seed data + const { totalDocs } = await payload.count({ + collection: 'plugin-collection', + where: { id: { equals: 'seeded-by-plugin' } }, + }) + + if (totalDocs === 0) { + await payload.create({ + collection: 'plugin-collection', + data: { id: 'seeded-by-plugin' }, + }) + } + } + + return config + } +``` + +## Best Practices + +### Preserve Existing Config + +```typescript +// ✅ Good +collections: [...(config.collections || []), newCollection] + +// ❌ Bad +collections: [newCollection] +``` + +### Respect User Overrides + +```typescript +const collection: CollectionConfig = { + slug: 'redirects', + fields: defaultFields, + ...options.overrides, // User overrides last +} +``` + +### Hook Composition + +```typescript +hooks: { + ...collection.hooks, + afterChange: [ + myHook, + ...(collection.hooks?.afterChange || []), + ], +} +``` + +### Type Safety + +```typescript +import type { Config, Plugin, CollectionConfig, Field } from 'payload' +``` diff --git a/templates/with-cloudflare-d1/.cursor/rules/queries.md b/templates/with-cloudflare-d1/.cursor/rules/queries.md new file mode 100644 index 00000000000..4920ec85f09 --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/queries.md @@ -0,0 +1,223 @@ +--- +title: Queries +description: Local API, REST, and GraphQL query patterns +tags: [payload, queries, local-api, rest, graphql] +--- + +# Payload CMS Queries + +## Query Operators + +```typescript +// Equals +{ color: { equals: 'blue' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater/less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In/not in +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (point fields) +{ location: { near: [10, 20, 5000] } } // [lng, lat, maxDistance] +``` + +## AND/OR Logic + +```typescript +{ + or: [ + { color: { equals: 'mint' } }, + { + and: [ + { color: { equals: 'white' } }, + { featured: { equals: false } }, + ], + }, + ], +} +``` + +## Nested Properties + +```typescript +{ + 'author.role': { equals: 'editor' }, + 'meta.featured': { exists: true }, +} +``` + +## Local API + +```typescript +// Find documents +const posts = await payload.find({ + collection: 'posts', + where: { + status: { equals: 'published' }, + 'author.name': { contains: 'john' }, + }, + depth: 2, // Populate relationships + limit: 10, + page: 1, + sort: '-createdAt', + locale: 'en', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const post = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { + status: 'published', + }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) + +// Count +const count = await payload.count({ + collection: 'posts', + where: { + status: { equals: 'published' }, + }, +}) +``` + +## Access Control in Local API + +**CRITICAL**: Local API bypasses access control by default (`overrideAccess: true`). + +```typescript +// ❌ WRONG: User is passed but access control is bypassed +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + // Result: Operation runs with ADMIN privileges +}) + +// ✅ CORRECT: Respects user's access control permissions +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + overrideAccess: false, // Required to enforce access control +}) + +// Administrative operation (intentionally bypass access control) +const allPosts = await payload.find({ + collection: 'posts', + // No user parameter, overrideAccess defaults to true +}) +``` + +**When to use `overrideAccess: false`:** + +- Performing operations on behalf of a user +- Testing access control logic +- API routes that should respect user permissions + +## REST API + +```typescript +import { stringify } from 'qs-esm' + +const query = { + status: { equals: 'published' }, +} + +const queryString = stringify( + { + where: query, + depth: 2, + limit: 10, + }, + { addQueryPrefix: true }, +) + +const response = await fetch(`https://api.example.com/api/posts${queryString}`) +const data = await response.json() +``` + +### REST Endpoints + +``` +GET /api/{collection} - Find documents +GET /api/{collection}/{id} - Find by ID +POST /api/{collection} - Create +PATCH /api/{collection}/{id} - Update +DELETE /api/{collection}/{id} - Delete +GET /api/{collection}/count - Count documents + +GET /api/globals/{slug} - Get global +POST /api/globals/{slug} - Update global +``` + +## GraphQL + +```graphql +query { + Posts(where: { status: { equals: published } }, limit: 10, sort: "-createdAt") { + docs { + id + title + author { + name + } + } + totalDocs + hasNextPage + } +} + +mutation { + createPost(data: { title: "New Post", status: draft }) { + id + title + } +} +``` + +## Performance Best Practices + +- Set `maxDepth` on relationships to prevent over-fetching +- Use `select` to limit returned fields +- Index frequently queried fields +- Use `virtual` fields for computed data +- Cache expensive operations in hook `context` diff --git a/templates/with-cloudflare-d1/.cursor/rules/security-critical.mdc b/templates/with-cloudflare-d1/.cursor/rules/security-critical.mdc new file mode 100644 index 00000000000..adf5d9e225d --- /dev/null +++ b/templates/with-cloudflare-d1/.cursor/rules/security-critical.mdc @@ -0,0 +1,122 @@ +--- +title: Critical Security Patterns +description: The three most important security patterns in Payload CMS +tags: [payload, security, critical, access-control, transactions, hooks] +priority: high +--- + +# CRITICAL SECURITY PATTERNS + +These are the three most critical security patterns that MUST be followed in every Payload CMS project. + +## 1. Local API Access Control (MOST IMPORTANT) + +**By default, Local API operations bypass ALL access control**, even when passing a user. + +```typescript +// ❌ SECURITY BUG: Passes user but ignores their permissions +await payload.find({ + collection: 'posts', + user: someUser, // Access control is BYPASSED! +}) + +// ✅ SECURE: Actually enforces the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED for access control +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**When to use each:** + +- `overrideAccess: true` (default) - Server-side operations you trust (cron jobs, system tasks) +- `overrideAccess: false` - When operating on behalf of a user (API routes, webhooks) + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +## 2. Transaction Safety in Hooks + +**Nested operations in hooks without `req` break transaction atomicity.** + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ] +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ] +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +## 3. Prevent Infinite Hook Loops + +**Hooks triggering operations that trigger the same hooks create infinite loops.** + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ] +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ] +} +``` + +**Rule**: Use `req.context` flags to prevent hook loops diff --git a/templates/with-cloudflare-d1/AGENTS.md b/templates/with-cloudflare-d1/AGENTS.md new file mode 100644 index 00000000000..633b29b1f61 --- /dev/null +++ b/templates/with-cloudflare-d1/AGENTS.md @@ -0,0 +1,1141 @@ +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default +6. **Access Control**: Ensure roles exist when modifiyng collection or globals with access controls + +### Code Validation + +- To validate typescript correctness after modifying code run `tsc --noEmit` +- Generate import maps after creating or modifying components. + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Configuration + +### Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Collections + +### Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +### Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Fields + +### Common Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## CRITICAL SECURITY PATTERNS + +### 1. Local API Access Control (MOST IMPORTANT) + +```typescript +// ❌ SECURITY BUG: Access control bypassed +await payload.find({ + collection: 'posts', + user: someUser, // Ignored! Operation runs with ADMIN privileges +}) + +// ✅ SECURE: Enforces user permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +### 2. Transaction Safety in Hooks + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ], +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ], +} +``` + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +### 3. Prevent Infinite Hook Loops + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ], +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ], +} +``` + +## Access Control + +### Collection-Level Access + +```typescript +import type { Access } from 'payload' + +// Boolean return +const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Query constraint (row-level security) +const ownPostsOnly: Access = ({ req: { user } }) => { + if (!user) return false + if (user?.roles?.includes('admin')) return true + + return { + author: { equals: user.id }, + } +} + +// Async access check +const projectMemberAccess: Access = async ({ req, id }) => { + const { user, payload } = req + + if (!user) return false + if (user.roles?.includes('admin')) return true + + const project = await payload.findByID({ + collection: 'projects', + id: id as string, + depth: 0, + }) + + return project.members?.includes(user.id) +} +``` + +### Field-Level Access + +```typescript +// Field access ONLY returns boolean (no query constraints) +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +### Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Hooks + +### Common Hook Patterns + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Queries + +### Local API + +```typescript +// Find with complex query +const posts = await payload.find({ + collection: 'posts', + where: { + and: [{ status: { equals: 'published' } }, { 'author.name': { contains: 'john' } }], + }, + depth: 2, // Populate relationships + limit: 10, + sort: '-createdAt', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const newPost = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { status: 'published' }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) +``` + +### Query Operators + +```typescript +// Equals +{ status: { equals: 'published' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater than / less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In array +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (geospatial) +{ location: { near: [-122.4194, 37.7749, 10000] } } +``` + +### AND/OR Logic + +```typescript +{ + or: [ + { status: { equals: 'published' } }, + { author: { equals: user.id } }, + ], +} + +{ + and: [ + { status: { equals: 'published' } }, + { featured: { equals: true } }, + ], +} +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Components + +The Admin Panel can be extensively customized using React Components. Custom Components can be Server Components (default) or Client Components. + +### Defining Components + +Components are defined using **file paths** (not direct imports) in your config: + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + // Logo and branding + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + + // Navigation + Nav: '/components/CustomNav', + beforeNavLinks: ['/components/CustomNavItem'], + afterNavLinks: ['/components/NavFooter'], + + // Header + header: ['/components/AnnouncementBanner'], + actions: ['/components/ClearCache', '/components/Preview'], + + // Dashboard + beforeDashboard: ['/components/WelcomeMessage'], + afterDashboard: ['/components/Analytics'], + + // Auth + beforeLogin: ['/components/SSOButtons'], + logout: { Button: '/components/LogoutButton' }, + + // Settings + settingsMenu: ['/components/SettingsMenu'], + + // Views + views: { + dashboard: { Component: '/components/CustomDashboard' }, + }, + }, + }, +}) +``` + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Server vs Client Components + +**All components are Server Components by default** (can use Local API directly): + +```tsx +// Server Component (default) +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const posts = await payload.find({ collection: 'posts' }) + return
{posts.totalDocs} posts
+} + +export default MyServerComponent +``` + +**Client Components** need the `'use client'` directive: + +```tsx +'use client' +import { useState } from 'react' +import { useAuth } from '@payloadcms/ui' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + const { user } = useAuth() + + return ( + + ) +} +``` + +### Using Hooks (Client Components Only) + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Document info (id, collection, etc.) + useField, // Field value and setter + useForm, // Form state + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +### Collection/Global Components + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/SaveDraft', + PublishButton: '/components/Publish', + }, + + // List view + list: { + Header: '/components/ListHeader', + beforeList: ['/components/BulkActions'], + afterList: ['/components/ListFooter'], + }, + }, + }, +} +``` + +### Field Components + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + // Edit view field + Field: '/components/StatusField', + // List view cell + Cell: '/components/StatusCell', + // Field label + Label: '/components/StatusLabel', + // Field description + Description: '/components/StatusDescription', + // Error message + Error: '/components/StatusError', + }, + }, +} +``` + +**UI Field** (presentational only, no data): + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +### Performance Best Practices + +1. **Import correctly:** + + - Admin Panel: `import { Button } from '@payloadcms/ui'` + - Frontend: `import { Button } from '@payloadcms/ui/elements/Button'` + +2. **Optimize re-renders:** + + ```tsx + // ❌ BAD: Re-renders on every form change + const { fields } = useForm() + + // ✅ GOOD: Only re-renders when specific field changes + const value = useFormFields(([fields]) => fields[path]) + ``` + +3. **Prefer Server Components** - Only use Client Components when you need: + + - State (useState, useReducer) + - Effects (useEffect) + - Event handlers (onClick, onChange) + - Browser APIs (localStorage, window) + +4. **Minimize serialized props** - Server Components serialize props sent to client + +### Styling Components + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Content
+} +``` + +```scss +// Use Payload's CSS variables +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} + +// Import Payload's SCSS library +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +### Type Safety + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, + SelectFieldServerComponent, + // ... etc +} from 'payload' + +export const MyField: TextFieldClientComponent = (props) => { + // Fully typed props +} +``` + +### Import Map + +Payload auto-generates `app/(payload)/admin/importMap.js` to resolve component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Set custom location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Custom Endpoints + +```typescript +import type { Endpoint } from 'payload' +import { APIError } from 'payload' + +// Always check authentication +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} + +// Route parameters +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Drafts & Versions + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} + +// Create draft +await payload.create({ + collection: 'pages', + data: { title: 'Draft Page' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft if available +}) +``` + +## Field Type Guards + +```typescript +import { + fieldAffectsData, + fieldHasSubFields, + fieldIsArrayType, + fieldIsBlockType, + fieldSupportsMany, + fieldHasMaxDepth, +} from 'payload' + +function processField(field: Field) { + // Check if field stores data + if (fieldAffectsData(field)) { + console.log(field.name) // Safe to access + } + + // Check if field has nested fields + if (fieldHasSubFields(field)) { + field.fields.forEach(processField) // Safe to access + } + + // Check field type + if (fieldIsArrayType(field)) { + console.log(field.minRows, field.maxRows) + } + + // Check capabilities + if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') + } +} +``` + +## Plugins + +### Using Plugins + +```typescript +import { seoPlugin } from '@payloadcms/plugin-seo' +import { redirectsPlugin } from '@payloadcms/plugin-redirects' + +export default buildConfig({ + plugins: [ + seoPlugin({ + collections: ['posts', 'pages'], + }), + redirectsPlugin({ + collections: ['pages'], + }), + ], +}) +``` + +### Creating Plugins + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + collections?: string[] + enabled?: boolean +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...collection.fields, { name: 'pluginField', type: 'text' }], + } + } + return collection + }), + }) +``` + +## Best Practices + +### Security + +1. Always set `overrideAccess: false` when passing `user` to Local API +2. Field-level access only returns boolean (no query constraints) +3. Default to restrictive access, gradually add permissions +4. Never trust client-provided data +5. Use `saveToJWT: true` for roles to avoid database lookups + +### Performance + +1. Index frequently queried fields +2. Use `select` to limit returned fields +3. Set `maxDepth` on relationships to prevent over-fetching +4. Use query constraints over async operations in access control +5. Cache expensive operations in `req.context` + +### Data Integrity + +1. Always pass `req` to nested operations in hooks +2. Use context flags to prevent infinite hook loops +3. Enable transactions for MongoDB (requires replica set) and Postgres +4. Use `beforeValidate` for data formatting +5. Use `beforeChange` for business logic + +### Type Safety + +1. Run `generate:types` after schema changes +2. Import types from generated `payload-types.ts` +3. Type your user object: `import type { User } from '@/payload-types'` +4. Use `as const` for field options +5. Use field type guards for runtime type checking + +### Organization + +1. Keep collections in separate files +2. Extract access control to `access/` directory +3. Extract hooks to `hooks/` directory +4. Use reusable field factories for common patterns +5. Document complex access control with comments + +## Common Gotchas + +1. **Local API Default**: Access control bypassed unless `overrideAccess: false` +2. **Transaction Safety**: Missing `req` in nested operations breaks atomicity +3. **Hook Loops**: Operations in hooks can trigger the same hooks +4. **Field Access**: Cannot use query constraints, only boolean +5. **Relationship Depth**: Default depth is 2, set to 0 for IDs only +6. **Draft Status**: `_status` field auto-injected when drafts enabled +7. **Type Generation**: Types not updated until `generate:types` runs +8. **MongoDB Transactions**: Require replica set configuration +9. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +10. **Point Fields**: Not supported in SQLite + +## Additional Context Files + +For deeper exploration of specific topics, refer to the context files located in `.cursor/rules/`: + +### Available Context Files + +1. **`payload-overview.md`** - High-level architecture and core concepts + + - Payload structure and initialization + - Configuration fundamentals + - Database adapters overview + +2. **`security-critical.md`** - Critical security patterns (⚠️ IMPORTANT) + + - Local API access control + - Transaction safety in hooks + - Preventing infinite hook loops + +3. **`collections.md`** - Collection configurations + + - Basic collection patterns + - Auth collections with RBAC + - Upload collections + - Drafts and versioning + - Globals + +4. **`fields.md`** - Field types and patterns + + - All field types with examples + - Conditional fields + - Virtual fields + - Field validation + - Common field patterns + +5. **`field-type-guards.md`** - TypeScript field type utilities + + - Field type checking utilities + - Safe type narrowing + - Runtime field validation + +6. **`access-control.md`** - Permission patterns + + - Collection-level access + - Field-level access + - Row-level security + - RBAC patterns + - Multi-tenant access control + +7. **`access-control-advanced.md`** - Complex access patterns + + - Nested document access + - Cross-collection permissions + - Dynamic role hierarchies + - Performance optimization + +8. **`hooks.md`** - Lifecycle hooks + + - Collection hooks + - Field hooks + - Hook context patterns + - Common hook recipes + +9. **`queries.md`** - Database operations + + - Local API usage + - Query operators + - Complex queries with AND/OR + - Performance optimization + +10. **`endpoints.md`** - Custom API endpoints + + - REST endpoint patterns + - Authentication in endpoints + - Error handling + - Route parameters + +11. **`adapters.md`** - Database and storage adapters + + - MongoDB, PostgreSQL, SQLite patterns + - Storage adapter usage (S3, Azure, GCS, etc.) + - Custom adapter development + +12. **`plugin-development.md`** - Creating plugins + + - Plugin architecture + - Modifying configuration + - Plugin hooks + - Best practices + +13. **`components.md`** - Custom Components + + - Component types (Root, Collection, Global, Field) + - Server vs Client Components + - Component paths and definition + - Default and custom props + - Using hooks + - Performance best practices + - Styling components + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/with-cloudflare-d1/package.json b/templates/with-cloudflare-d1/package.json index e208eecbea6..3c71dbaf93f 100644 --- a/templates/with-cloudflare-d1/package.json +++ b/templates/with-cloudflare-d1/package.json @@ -26,16 +26,16 @@ }, "dependencies": { "@opennextjs/cloudflare": "^1.11.0", - "@payloadcms/db-d1-sqlite": "3.63.0", - "@payloadcms/next": "3.63.0", - "@payloadcms/richtext-lexical": "3.63.0", - "@payloadcms/storage-r2": "3.63.0", - "@payloadcms/ui": "3.63.0", + "@payloadcms/db-d1-sqlite": "3.68.5", + "@payloadcms/next": "3.68.5", + "@payloadcms/richtext-lexical": "3.68.5", + "@payloadcms/storage-r2": "3.68.5", + "@payloadcms/ui": "3.68.5", "cross-env": "^7.0.3", "dotenv": "16.4.7", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.63.0", + "payload": "3.68.5", "react": "19.2.1", "react-dom": "19.2.1" }, diff --git a/templates/with-cloudflare-d1/src/payload-types.ts b/templates/with-cloudflare-d1/src/payload-types.ts index 5b400164177..bb85eafc6d0 100644 --- a/templates/with-cloudflare-d1/src/payload-types.ts +++ b/templates/with-cloudflare-d1/src/payload-types.ts @@ -86,6 +86,7 @@ export interface Config { db: { defaultIDType: number; }; + fallbackLocale: null; globals: {}; globalsSelect: {}; locale: null; diff --git a/templates/with-postgres/.cursor/rules/access-control-advanced.md b/templates/with-postgres/.cursor/rules/access-control-advanced.md new file mode 100644 index 00000000000..68f52fd1287 --- /dev/null +++ b/templates/with-postgres/.cursor/rules/access-control-advanced.md @@ -0,0 +1,519 @@ +--- +title: Access Control - Advanced Patterns +description: Context-aware, time-based, subscription-based access, factory functions, templates +tags: [payload, access-control, security, advanced, performance] +priority: high +--- + +# Advanced Access Control Patterns + +Advanced access control patterns including context-aware access, time-based restrictions, factory functions, and production templates. + +## Context-Aware Access Patterns + +### Locale-Specific Access + +```typescript +import type { Access } from 'payload' + +export const localeSpecificAccess: Access = ({ req: { user, locale } }) => { + // Authenticated users can access all locales + if (user) return true + + // Public users can only access English content + if (locale === 'en') return true + + return false +} +``` + +### Device-Specific Access + +```typescript +export const mobileOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return /mobile|android|iphone/i.test(userAgent) +} + +export const desktopOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return !/mobile|android|iphone/i.test(userAgent) +} +``` + +### IP-Based Access + +```typescript +export const restrictedIpAccess = (allowedIps: string[]): Access => { + return ({ req: { headers } }) => { + const ip = headers?.get('x-forwarded-for') || headers?.get('x-real-ip') + return allowedIps.includes(ip || '') + } +} + +// Usage +const internalIps = ['192.168.1.0/24', '10.0.0.5'] + +export const InternalDocs: CollectionConfig = { + slug: 'internal-docs', + access: { + read: restrictedIpAccess(internalIps), + }, +} +``` + +## Time-Based Access Patterns + +### Today's Records Only + +```typescript +export const todayOnlyAccess: Access = ({ req: { user } }) => { + if (!user) return false + + const now = new Date() + const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000) + + return { + createdAt: { + greater_than_equal: startOfDay.toISOString(), + less_than: endOfDay.toISOString(), + }, + } +} +``` + +### Recent Records (Last N Days) + +```typescript +export const recentRecordsAccess = (days: number): Access => { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - days) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} + +// Usage: Users see only last 30 days, admins see all +export const Logs: CollectionConfig = { + slug: 'logs', + access: { + read: recentRecordsAccess(30), + }, +} +``` + +### Scheduled Content (Publish Date Range) + +```typescript +export const scheduledContentAccess: Access = ({ req: { user } }) => { + // Editors see all content + if (user?.roles?.includes('admin') || user?.roles?.includes('editor')) { + return true + } + + const now = new Date().toISOString() + + // Public sees only content within publish window + return { + and: [ + { publishDate: { less_than_equal: now } }, + { + or: [{ unpublishDate: { exists: false } }, { unpublishDate: { greater_than: now } }], + }, + ], + } +} +``` + +## Subscription-Based Access + +### Active Subscription Required + +```typescript +export const activeSubscriptionAccess: Access = async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + return subscription?.status === 'active' + } catch { + return false + } +} +``` + +### Subscription Tier-Based Access + +```typescript +export const tierBasedAccess = (requiredTier: string): Access => { + const tierHierarchy = ['free', 'basic', 'pro', 'enterprise'] + + return async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + if (subscription?.status !== 'active') return false + + const userTierIndex = tierHierarchy.indexOf(subscription.tier) + const requiredTierIndex = tierHierarchy.indexOf(requiredTier) + + return userTierIndex >= requiredTierIndex + } catch { + return false + } + } +} + +// Usage +export const EnterpriseFeatures: CollectionConfig = { + slug: 'enterprise-features', + access: { + read: tierBasedAccess('enterprise'), + }, +} +``` + +## Factory Functions + +### createRoleBasedAccess + +```typescript +export function createRoleBasedAccess(roles: string[]): Access { + return ({ req: { user } }) => { + if (!user) return false + return roles.some((role) => user.roles?.includes(role)) + } +} + +// Usage +const adminOrEditor = createRoleBasedAccess(['admin', 'editor']) +const moderatorAccess = createRoleBasedAccess(['admin', 'moderator']) +``` + +### createOrgScopedAccess + +```typescript +export function createOrgScopedAccess(allowAdmin = true): Access { + return ({ req: { user } }) => { + if (!user) return false + if (allowAdmin && user.roles?.includes('admin')) return true + + return { + organizationId: { in: user.organizationIds || [] }, + } + } +} + +// Usage +const orgScoped = createOrgScopedAccess() // Admins bypass +const strictOrgScoped = createOrgScopedAccess(false) // Admins also scoped +``` + +### createTeamBasedAccess + +```typescript +export function createTeamBasedAccess(teamField = 'teamId'): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + [teamField]: { in: user.teamIds || [] }, + } + } +} +``` + +### createTimeLimitedAccess + +```typescript +export function createTimeLimitedAccess(daysAccess: number): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - daysAccess) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} +``` + +## Configuration Templates + +### Public + Authenticated Collection + +```typescript +export const PublicAuthCollection: CollectionConfig = { + slug: 'posts', + access: { + // Only admins/editors can create + create: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Authenticated users see all, public sees only published + read: ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } + }, + + // Only admins/editors can update + update: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Only admins can delete + delete: ({ req: { user } }) => { + return user?.roles?.includes('admin') || false + }, + }, + versions: { + drafts: true, + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'content', type: 'richText', required: true }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], +} +``` + +### Self-Service Collection + +```typescript +export const SelfServiceCollection: CollectionConfig = { + slug: 'users', + auth: true, + access: { + // Admins can create users + create: ({ req: { user } }) => user?.roles?.includes('admin') || false, + + // Anyone can read user profiles + read: () => true, + + // Users can update self, admins can update anyone + update: ({ req: { user }, id }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + return user.id === id + }, + + // Only admins can delete + delete: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + fields: [ + { name: 'name', type: 'text', required: true }, + { name: 'email', type: 'email', required: true }, + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + access: { + // Only admins can read/update roles + read: ({ req: { user } }) => user?.roles?.includes('admin') || false, + update: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + }, + ], +} +``` + +## Performance Considerations + +### Avoid Async Operations in Hot Paths + +```typescript +// ❌ Slow: Multiple sequential async calls +export const slowAccess: Access = async ({ req: { user } }) => { + const org = await req.payload.findByID({ collection: 'orgs', id: user.orgId }) + const team = await req.payload.findByID({ collection: 'teams', id: user.teamId }) + const subscription = await req.payload.findByID({ collection: 'subs', id: user.subId }) + + return org.active && team.active && subscription.active +} + +// ✅ Fast: Use query constraints or cache in context +export const fastAccess: Access = ({ req: { user, context } }) => { + // Cache expensive lookups + if (!context.orgStatus) { + context.orgStatus = checkOrgStatus(user.orgId) + } + + return context.orgStatus +} +``` + +### Query Constraint Optimization + +```typescript +// ❌ Avoid: Non-indexed fields in constraints +export const slowQuery: Access = () => ({ + 'metadata.internalCode': { equals: 'ABC123' }, // Slow if not indexed +}) + +// ✅ Better: Use indexed fields +export const fastQuery: Access = () => ({ + status: { equals: 'active' }, // Indexed field + organizationId: { in: ['org1', 'org2'] }, // Indexed field +}) +``` + +### Field Access on Large Arrays + +```typescript +// ❌ Slow: Complex access on array fields +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: async ({ req }) => { + // Async call runs for EVERY array item + const result = await expensiveCheck() + return result + }, + }, + }, + ], +} + +// ✅ Fast: Simple checks or cache result +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: ({ req: { user }, context }) => { + // Cache once, reuse for all items + if (context.canReadSecret === undefined) { + context.canReadSecret = user?.roles?.includes('admin') + } + return context.canReadSecret + }, + }, + }, + ], +} +``` + +### Avoid N+1 Queries + +```typescript +// ❌ N+1 Problem: Query per access check +export const n1Access: Access = async ({ req, id }) => { + // Runs for EACH document in list + const doc = await req.payload.findByID({ collection: 'docs', id }) + return doc.isPublic +} + +// ✅ Better: Use query constraint to filter at DB level +export const efficientAccess: Access = () => { + return { isPublic: { equals: true } } +} +``` + +## Debugging Tips + +### Log Access Check Execution + +```typescript +export const debugAccess: Access = ({ req: { user }, id }) => { + console.log('Access check:', { + userId: user?.id, + userRoles: user?.roles, + docId: id, + timestamp: new Date().toISOString(), + }) + return true +} +``` + +### Verify Arguments Availability + +```typescript +export const checkArgsAccess: Access = (args) => { + console.log('Available arguments:', { + hasReq: 'req' in args, + hasUser: args.req?.user ? 'yes' : 'no', + hasId: args.id ? 'provided' : 'undefined', + hasData: args.data ? 'provided' : 'undefined', + }) + return true +} +``` + +### Test Access Without User + +```typescript +// In test/development +const testAccess = await payload.find({ + collection: 'posts', + overrideAccess: false, // Enforce access control + user: undefined, // Simulate no user +}) + +console.log('Public access result:', testAccess.docs.length) +``` + +## Best Practices + +1. **Default Deny**: Start with restrictive access, gradually add permissions +2. **Type Guards**: Use TypeScript for user type safety +3. **Validate Data**: Never trust frontend-provided IDs or data +4. **Async for Critical Checks**: Use async operations for important security decisions +5. **Consistent Logic**: Apply same rules at field and collection levels +6. **Test Edge Cases**: Test with no user, wrong user, admin user scenarios +7. **Monitor Access**: Log failed access attempts for security review +8. **Regular Audit**: Review access rules quarterly or after major changes +9. **Cache Wisely**: Use `req.context` for expensive operations +10. **Document Intent**: Add comments explaining complex access rules +11. **Avoid Secrets in Client**: Never expose sensitive logic to client-side +12. **Handle Errors Gracefully**: Access functions should return `false` on error, not throw +13. **Test Local API**: Remember to set `overrideAccess: false` when testing +14. **Consider Performance**: Measure impact of async operations +15. **Principle of Least Privilege**: Grant minimum access required + +## Performance Summary + +**Minimize Async Operations**: Use query constraints over async lookups when possible + +**Cache Expensive Checks**: Store results in `req.context` for reuse + +**Index Query Fields**: Ensure fields in query constraints are indexed + +**Avoid Complex Logic in Array Fields**: Simple boolean checks preferred + +**Use Query Constraints**: Let database filter rather than loading all records diff --git a/templates/with-postgres/.cursor/rules/access-control.md b/templates/with-postgres/.cursor/rules/access-control.md new file mode 100644 index 00000000000..7b9a0a4ba5c --- /dev/null +++ b/templates/with-postgres/.cursor/rules/access-control.md @@ -0,0 +1,225 @@ +--- +title: Access Control +description: Collection, field, and global access control patterns +tags: [payload, access-control, security, permissions, rbac] +--- + +# Payload CMS Access Control + +## Access Control Layers + +1. **Collection-Level**: Controls operations on entire documents (create, read, update, delete, admin) +2. **Field-Level**: Controls access to individual fields (create, read, update) +3. **Global-Level**: Controls access to global documents (read, update) + +## Collection Access Control + +```typescript +import type { Access } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + // Boolean: Only authenticated users can create + create: ({ req: { user } }) => Boolean(user), + + // Query constraint: Public sees published, users see all + read: ({ req: { user } }) => { + if (user) return true + return { status: { equals: 'published' } } + }, + + // User-specific: Admins or document owner + update: ({ req: { user }, id }) => { + if (user?.roles?.includes('admin')) return true + return { author: { equals: user?.id } } + }, + + // Async: Check related data + delete: async ({ req, id }) => { + const hasComments = await req.payload.count({ + collection: 'comments', + where: { post: { equals: id } }, + }) + return hasComments === 0 + }, + }, +} +``` + +## Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Row-Level Security + +```typescript +// Organization-scoped access +export const organizationScoped: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + + // Users see only their organization's data + return { + organization: { + equals: user?.organization, + }, + } +} + +// Team-based access +export const teamMemberAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + 'team.members': { + contains: user.id, + }, + } +} +``` + +## Field Access Control + +**Field access ONLY returns boolean** (no query constraints). + +```typescript +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +## RBAC Pattern + +Payload does NOT provide a roles system by default. Add a `roles` field to your auth collection: + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Multi-Tenant Access Control + +```typescript +interface User { + id: string + tenantId: string + roles?: string[] +} + +const tenantAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('super-admin')) return true + + return { + tenant: { + equals: (user as User).tenantId, + }, + } +} + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + create: tenantAccess, + read: tenantAccess, + update: tenantAccess, + delete: tenantAccess, + }, + fields: [ + { + name: 'tenant', + type: 'text', + required: true, + access: { + update: ({ req: { user } }) => user?.roles?.includes('super-admin'), + }, + hooks: { + beforeChange: [ + ({ req, operation, value }) => { + if (operation === 'create' && !value) { + return (req.user as User)?.tenantId + } + return value + }, + ], + }, + }, + ], +} +``` + +## Important Notes + +1. **Local API Default**: Access control is **skipped by default** in Local API (`overrideAccess: true`). When passing a `user` parameter, you must set `overrideAccess: false`: + +```typescript +// ❌ WRONG: Passes user but bypasses access control +await payload.find({ + collection: 'posts', + user: someUser, +}) + +// ✅ CORRECT: Respects the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // Required to enforce access control +}) +``` + +2. **Field Access Limitations**: Field-level access does NOT support query constraints - only boolean returns. + +3. **Admin Panel Visibility**: The `admin` access control determines if a collection appears in the admin panel for a user. diff --git a/templates/with-postgres/.cursor/rules/adapters.md b/templates/with-postgres/.cursor/rules/adapters.md new file mode 100644 index 00000000000..49b8b3367fc --- /dev/null +++ b/templates/with-postgres/.cursor/rules/adapters.md @@ -0,0 +1,209 @@ +--- +title: Database Adapters & Transactions +description: Database adapters, storage, email, and transaction patterns +tags: [payload, database, mongodb, postgres, sqlite, transactions] +--- + +# Payload CMS Adapters + +## Database Adapters + +### MongoDB + +```typescript +import { mongooseAdapter } from '@payloadcms/db-mongodb' + +export default buildConfig({ + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +### Postgres + +```typescript +import { postgresAdapter } from '@payloadcms/db-postgres' + +export default buildConfig({ + db: postgresAdapter({ + pool: { + connectionString: process.env.DATABASE_URI, + }, + push: false, // Don't auto-push schema changes + migrationDir: './migrations', + }), +}) +``` + +### SQLite + +```typescript +import { sqliteAdapter } from '@payloadcms/db-sqlite' + +export default buildConfig({ + db: sqliteAdapter({ + client: { + url: 'file:./payload.db', + }, + transactionOptions: {}, // Enable transactions (disabled by default) + }), +}) +``` + +## Transactions + +Payload automatically uses transactions for all-or-nothing database operations. + +### Threading req Through Operations + +**CRITICAL**: When performing nested operations in hooks, always pass `req` to maintain transaction context. + +```typescript +// ✅ CORRECT: Thread req through nested operations +const resaveChildren: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + // Find children - pass req + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + req, // Maintains transaction context + }) + + // Update each child - pass req + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + req, // Same transaction as parent operation + }) + } +} + +// ❌ WRONG: Missing req breaks transaction +const brokenHook: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + // Missing req - separate transaction or no transaction + }) + + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + // Missing req - if parent operation fails, these updates persist + }) + } +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +### Manual Transaction Control + +```typescript +const transactionID = await payload.db.beginTransaction() +try { + await payload.create({ + collection: 'orders', + data: orderData, + req: { transactionID }, + }) + await payload.update({ + collection: 'inventory', + id: itemId, + data: { stock: newStock }, + req: { transactionID }, + }) + await payload.db.commitTransaction(transactionID) +} catch (error) { + await payload.db.rollbackTransaction(transactionID) + throw error +} +``` + +## Storage Adapters + +Available storage adapters: + +- **@payloadcms/storage-s3** - AWS S3 +- **@payloadcms/storage-azure** - Azure Blob Storage +- **@payloadcms/storage-gcs** - Google Cloud Storage +- **@payloadcms/storage-r2** - Cloudflare R2 +- **@payloadcms/storage-vercel-blob** - Vercel Blob +- **@payloadcms/storage-uploadthing** - Uploadthing + +### AWS S3 + +```typescript +import { s3Storage } from '@payloadcms/storage-s3' + +export default buildConfig({ + plugins: [ + s3Storage({ + collections: { + media: true, + }, + bucket: process.env.S3_BUCKET, + config: { + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + region: process.env.S3_REGION, + }, + }), + ], +}) +``` + +## Email Adapters + +### Nodemailer (SMTP) + +```typescript +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' + +export default buildConfig({ + email: nodemailerAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + transportOptions: { + host: process.env.SMTP_HOST, + port: 587, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }, + }), +}) +``` + +### Resend + +```typescript +import { resendAdapter } from '@payloadcms/email-resend' + +export default buildConfig({ + email: resendAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + apiKey: process.env.RESEND_API_KEY, + }), +}) +``` + +## Important Notes + +1. **MongoDB Transactions**: Require replica set configuration +2. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +3. **Pass req**: Always pass `req` to nested operations in hooks for transaction safety +4. **Point Fields**: Not supported in SQLite diff --git a/templates/with-postgres/.cursor/rules/collections.md b/templates/with-postgres/.cursor/rules/collections.md new file mode 100644 index 00000000000..af625108e60 --- /dev/null +++ b/templates/with-postgres/.cursor/rules/collections.md @@ -0,0 +1,171 @@ +--- +title: Collections +description: Collection configurations and patterns +tags: [payload, collections, auth, upload, drafts] +--- + +# Payload CMS Collections + +## Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +## Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Upload Collection + +```typescript +export const Media: CollectionConfig = { + slug: 'media', + upload: { + staticDir: 'media', + mimeTypes: ['image/*'], + imageSizes: [ + { + name: 'thumbnail', + width: 400, + height: 300, + position: 'centre', + }, + { + name: 'card', + width: 768, + height: 1024, + }, + ], + adminThumbnail: 'thumbnail', + focalPoint: true, + crop: true, + }, + access: { + read: () => true, + }, + fields: [ + { + name: 'alt', + type: 'text', + required: true, + }, + ], +} +``` + +## Versioning & Drafts + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} +``` + +### Draft API Usage + +```typescript +// Create draft +await payload.create({ + collection: 'posts', + data: { title: 'Draft Post' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft version if exists +}) +``` + +## Globals + +Globals are single-instance documents (not collections). + +```typescript +import type { GlobalConfig } from 'payload' + +export const Header: GlobalConfig = { + slug: 'header', + label: 'Header', + admin: { + group: 'Settings', + }, + fields: [ + { + name: 'logo', + type: 'upload', + relationTo: 'media', + required: true, + }, + { + name: 'nav', + type: 'array', + maxRows: 8, + fields: [ + { + name: 'link', + type: 'relationship', + relationTo: 'pages', + }, + { + name: 'label', + type: 'text', + }, + ], + }, + ], +} +``` diff --git a/templates/with-postgres/.cursor/rules/components.md b/templates/with-postgres/.cursor/rules/components.md new file mode 100644 index 00000000000..8610b8d7b33 --- /dev/null +++ b/templates/with-postgres/.cursor/rules/components.md @@ -0,0 +1,794 @@ +# Custom Components in Payload CMS + +Custom Components allow you to fully customize the Admin Panel by swapping in your own React components. You can replace nearly every part of the interface or add entirely new functionality. + +## Component Types + +There are four main types of Custom Components: + +1. **Root Components** - Affect the Admin Panel globally (logo, nav, header) +2. **Collection Components** - Specific to collection views +3. **Global Components** - Specific to global document views +4. **Field Components** - Custom field UI and cells + +## Defining Custom Components + +### Component Paths + +Components are defined using file paths (not direct imports) to keep the config lightweight and Node.js compatible. + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + logout: { + Button: '/src/components/Logout#MyComponent', // Named export + }, + Nav: '/src/components/Nav', // Default export + }, + }, +}) +``` + +**Component Path Rules:** + +1. Paths are relative to project root (or `config.admin.importMap.baseDir`) +2. For **named exports**: append `#ExportName` or use `exportName` property +3. For **default exports**: no suffix needed +4. File extensions can be omitted + +### Component Config Object + +Instead of a string path, you can pass a config object: + +```typescript +{ + logout: { + Button: { + path: '/src/components/Logout', + exportName: 'MyComponent', + clientProps: { customProp: 'value' }, + serverProps: { asyncData: someData }, + }, + }, +} +``` + +**Config Properties:** + +| Property | Description | +| ------------- | ----------------------------------------------------- | +| `path` | File path to component (named exports via `#`) | +| `exportName` | Named export (alternative to `#` in path) | +| `clientProps` | Props for Client Components (must be serializable) | +| `serverProps` | Props for Server Components (can be non-serializable) | + +### Setting Base Directory + +```typescript +import path from 'path' +import { fileURLToPath } from 'node:url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), // Set base directory + }, + components: { + Nav: '/components/Nav', // Now relative to src/ + }, + }, +}) +``` + +## Server vs Client Components + +**All components are React Server Components by default.** + +### Server Components (Default) + +Can use Local API directly, perform async operations, and access full Payload instance. + +```tsx +import React from 'react' +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const page = await payload.findByID({ + collection: 'pages', + id: '123', + }) + + return

{page.title}

+} + +export default MyServerComponent +``` + +### Client Components + +Use the `'use client'` directive for interactivity, hooks, state, etc. + +```tsx +'use client' +import React, { useState } from 'react' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + + return +} +``` + +**Important:** Client Components cannot receive non-serializable props (functions, class instances, etc.). Payload automatically strips these when passing to client components. + +## Default Props + +All Custom Components receive these props by default: + +| Prop | Description | Type | +| --------- | ---------------------------------------- | --------- | +| `payload` | Payload instance (Local API access) | `Payload` | +| `i18n` | Internationalization object | `I18n` | +| `locale` | Current locale (if localization enabled) | `string` | + +**Server Component Example:** + +```tsx +async function MyComponent({ payload, i18n, locale }) { + const data = await payload.find({ + collection: 'posts', + locale, + }) + + return
{data.docs.length} posts
+} +``` + +**Client Component Example:** + +```tsx +'use client' +import { usePayload, useLocale, useTranslation } from '@payloadcms/ui' + +export function MyComponent() { + // Access via hooks in client components + const { getLocal, getByID } = usePayload() + const locale = useLocale() + const { t, i18n } = useTranslation() + + return
{t('myKey')}
+} +``` + +## Custom Props + +Pass additional props using `clientProps` or `serverProps`: + +```typescript +{ + logout: { + Button: { + path: '/components/Logout', + clientProps: { + buttonText: 'Sign Out', + onLogout: () => console.log('Logged out'), + }, + }, + }, +} +``` + +Receive in component: + +```tsx +'use client' +export function Logout({ buttonText, onLogout }) { + return +} +``` + +## Root Components + +Root Components affect the entire Admin Panel. + +### Available Root Components + +| Component | Description | Config Path | +| ----------------- | -------------------------------- | ---------------------------------- | +| `Nav` | Entire navigation sidebar | `admin.components.Nav` | +| `graphics.Icon` | Small icon (used in nav) | `admin.components.graphics.Icon` | +| `graphics.Logo` | Full logo (used on login) | `admin.components.graphics.Logo` | +| `logout.Button` | Logout button | `admin.components.logout.Button` | +| `actions` | Header actions (array) | `admin.components.actions` | +| `header` | Above header (array) | `admin.components.header` | +| `beforeDashboard` | Before dashboard content (array) | `admin.components.beforeDashboard` | +| `afterDashboard` | After dashboard content (array) | `admin.components.afterDashboard` | +| `beforeLogin` | Before login form (array) | `admin.components.beforeLogin` | +| `afterLogin` | After login form (array) | `admin.components.afterLogin` | +| `beforeNavLinks` | Before nav links (array) | `admin.components.beforeNavLinks` | +| `afterNavLinks` | After nav links (array) | `admin.components.afterNavLinks` | +| `settingsMenu` | Settings menu items (array) | `admin.components.settingsMenu` | +| `providers` | Custom React Context providers | `admin.components.providers` | +| `views` | Custom views (dashboard, etc.) | `admin.components.views` | + +### Example: Custom Logo + +```typescript +export default buildConfig({ + admin: { + components: { + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + }, + }, +}) +``` + +```tsx +// components/Logo.tsx +export default function Logo() { + return My Brand +} +``` + +### Example: Header Actions + +```typescript +export default buildConfig({ + admin: { + components: { + actions: ['/components/ClearCacheButton', '/components/PreviewButton'], + }, + }, +}) +``` + +```tsx +// components/ClearCacheButton.tsx +'use client' +export default function ClearCacheButton() { + return ( + + ) +} +``` + +## Collection Components + +Collection Components are specific to a collection's views. + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view components + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/CustomSaveDraft', + PublishButton: '/components/CustomPublish', + }, + + // List view components + list: { + Header: '/components/PostsListHeader', + beforeList: ['/components/ListFilters'], + afterList: ['/components/ListFooter'], + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Global Components + +Similar to Collection Components but for Global documents. + +```typescript +import type { GlobalConfig } from 'payload' + +export const Settings: GlobalConfig = { + slug: 'settings', + admin: { + components: { + edit: { + PreviewButton: '/components/SettingsPreview', + SaveButton: '/components/SettingsSave', + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Field Components + +Customize how fields render in Edit and List views. + +### Field Component (Edit View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Field: '/components/StatusField', + }, + }, +} +``` + +```tsx +// components/StatusField.tsx +'use client' +import { useField } from '@payloadcms/ui' +import type { SelectFieldClientComponent } from 'payload' + +export const StatusField: SelectFieldClientComponent = ({ path, field }) => { + const { value, setValue } = useField({ path }) + + return ( +
+ + +
+ ) +} +``` + +### Cell Component (List View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Cell: '/components/StatusCell', + }, + }, +} +``` + +```tsx +// components/StatusCell.tsx +import type { SelectFieldCellComponent } from 'payload' + +export const StatusCell: SelectFieldCellComponent = ({ data, cellData }) => { + const isPublished = cellData === 'published' + + return ( + + {cellData} + + ) +} +``` + +### UI Field (Presentational Only) + +Special field type for adding custom UI without affecting data: + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +```tsx +// components/RefundButton.tsx +'use client' +import { useDocumentInfo } from '@payloadcms/ui' + +export default function RefundButton() { + const { id } = useDocumentInfo() + + return ( + + ) +} +``` + +## Using Hooks + +Payload provides many React hooks for Client Components: + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Current document info (id, slug, etc.) + useField, // Field value and setValue + useForm, // Form state and dispatch + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +**Important:** These hooks only work in Client Components within the Admin Panel context. + +## Accessing Payload Config + +**In Server Components:** + +```tsx +async function MyServerComponent({ payload }) { + const { config } = payload + return
{config.serverURL}
+} +``` + +**In Client Components:** + +```tsx +'use client' +import { useConfig } from '@payloadcms/ui' + +export function MyClientComponent() { + const { config } = useConfig() // Client-safe config + return
{config.serverURL}
+} +``` + +**Important:** Client Components receive a serializable version of the config (functions, validation, etc. are stripped). + +## Field Config Access + +**Server Component:** + +```tsx +import type { TextFieldServerComponent } from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = ({ field }) => { + return
Field name: {field.name}
+} +``` + +**Client Component:** + +```tsx +'use client' +import type { TextFieldClientComponent } from 'payload' + +export const MyFieldComponent: TextFieldClientComponent = ({ clientField }) => { + // clientField has non-serializable props removed + return
Field name: {clientField.name}
+} +``` + +## Translations (i18n) + +**Server Component:** + +```tsx +import { getTranslation } from '@payloadcms/translations' + +async function MyServerComponent({ i18n }) { + const translatedTitle = getTranslation(myTranslation, i18n) + return

{translatedTitle}

+} +``` + +**Client Component:** + +```tsx +'use client' +import { useTranslation } from '@payloadcms/ui' + +export function MyClientComponent() { + const { t, i18n } = useTranslation() + + return ( +
+

{t('namespace:key', { variable: 'value' })}

+

Language: {i18n.language}

+
+ ) +} +``` + +## Styling Components + +### Using CSS Variables + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Custom Component
+} +``` + +```scss +// styles.scss +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} +``` + +### Importing Payload SCSS + +```scss +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +## Common Patterns + +### Conditional Field Visibility + +```tsx +'use client' +import { useFormFields } from '@payloadcms/ui' +import type { TextFieldClientComponent } from 'payload' + +export const ConditionalField: TextFieldClientComponent = ({ path }) => { + const showField = useFormFields(([fields]) => fields.enableFeature?.value) + + if (!showField) return null + + return +} +``` + +### Loading Data from API + +```tsx +'use client' +import { useState, useEffect } from 'react' + +export function DataLoader() { + const [data, setData] = useState(null) + + useEffect(() => { + fetch('/api/custom-data') + .then((res) => res.json()) + .then(setData) + }, []) + + return
{JSON.stringify(data)}
+} +``` + +### Using Local API in Server Components + +```tsx +import type { Payload } from 'payload' + +async function RelatedPosts({ payload, id }: { payload: Payload; id: string }) { + const post = await payload.findByID({ + collection: 'posts', + id, + depth: 0, + }) + + const related = await payload.find({ + collection: 'posts', + where: { + category: { equals: post.category }, + id: { not_equals: id }, + }, + limit: 5, + }) + + return ( +
+

Related Posts

+
    + {related.docs.map((doc) => ( +
  • {doc.title}
  • + ))} +
+
+ ) +} + +export default RelatedPosts +``` + +## Performance Best Practices + +### 1. Minimize Client Bundle Size + +```tsx +// ❌ BAD: Imports entire package +'use client' +import { Button } from '@payloadcms/ui' + +// ✅ GOOD: Tree-shakeable import for frontend +import { Button } from '@payloadcms/ui/elements/Button' +``` + +**Rule:** In Admin Panel UI, import from `@payloadcms/ui`. In frontend code, use specific paths. + +### 2. Optimize Re-renders + +```tsx +// ❌ BAD: Re-renders on every form change +'use client' +import { useForm } from '@payloadcms/ui' + +export function MyComponent() { + const { fields } = useForm() + // Re-renders on ANY field change +} + +// ✅ GOOD: Only re-renders when specific field changes +;('use client') +import { useFormFields } from '@payloadcms/ui' + +export function MyComponent({ path }) { + const value = useFormFields(([fields]) => fields[path]) + // Only re-renders when this field changes +} +``` + +### 3. Use Server Components When Possible + +```tsx +// ✅ GOOD: No JavaScript sent to client +async function PostCount({ payload }) { + const { totalDocs } = await payload.find({ + collection: 'posts', + limit: 0, + }) + + return

{totalDocs} posts

+} + +// Only use client components when you need: +// - State (useState, useReducer) +// - Effects (useEffect) +// - Event handlers (onClick, onChange) +// - Browser APIs (localStorage, window) +``` + +### 4. React Best Practices + +- Use React.memo() for expensive components +- Implement proper key props in lists +- Avoid inline function definitions in renders +- Use Suspense boundaries for async operations + +## Import Map + +Payload generates an import map at `app/(payload)/admin/importMap.js` that resolves all component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Override location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Type Safety + +Use Payload's TypeScript types for components: + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, +} from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = (props) => { + // Fully typed props +} +``` + +## Troubleshooting + +### "useConfig is undefined" or similar hook errors + +**Cause:** Dependency version mismatch between Payload packages. + +**Solution:** Pin all `@payloadcms/*` packages to the exact same version: + +```json +{ + "dependencies": { + "payload": "3.0.0", + "@payloadcms/ui": "3.0.0", + "@payloadcms/richtext-lexical": "3.0.0" + } +} +``` + +### Component not loading + +1. Check file path is correct (relative to baseDir) +2. Verify named export syntax: `/path/to/file#ExportName` +3. Run `payload generate:importmap` to regenerate +4. Check for TypeScript errors in component file + +## Resources + +- [Custom Components Docs](https://payloadcms.com/docs/custom-components/overview) +- [Root Components](https://payloadcms.com/docs/custom-components/root-components) +- [Custom Views](https://payloadcms.com/docs/custom-components/custom-views) +- [React Hooks](https://payloadcms.com/docs/admin/react-hooks) +- [Custom CSS](https://payloadcms.com/docs/admin/customizing-css) diff --git a/templates/with-postgres/.cursor/rules/endpoints.md b/templates/with-postgres/.cursor/rules/endpoints.md new file mode 100644 index 00000000000..8a2481dbe5d --- /dev/null +++ b/templates/with-postgres/.cursor/rules/endpoints.md @@ -0,0 +1,236 @@ +--- +title: Custom Endpoints +description: Custom REST API endpoints with authentication and helpers +tags: [payload, endpoints, api, routes, webhooks] +--- + +# Payload Custom Endpoints + +## Basic Endpoint Pattern + +Custom endpoints are **not authenticated by default**. Always check `req.user`. + +```typescript +import { APIError } from 'payload' +import type { Endpoint } from 'payload' + +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} +``` + +## Route Parameters + +```typescript +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Request Body Handling + +```typescript +// Manual JSON parsing +export const createEndpoint: Endpoint = { + path: '/create', + method: 'post', + handler: async (req) => { + const data = await req.json() + + const result = await req.payload.create({ + collection: 'posts', + data, + }) + + return Response.json(result) + }, +} + +// Using helper (handles JSON + files) +import { addDataAndFileToRequest } from 'payload' + +export const uploadEndpoint: Endpoint = { + path: '/upload', + method: 'post', + handler: async (req) => { + await addDataAndFileToRequest(req) + + // req.data contains parsed body + // req.file contains uploaded file (if multipart) + + const result = await req.payload.create({ + collection: 'media', + data: req.data, + file: req.file, + }) + + return Response.json(result) + }, +} +``` + +## Query Parameters + +```typescript +export const searchEndpoint: Endpoint = { + path: '/search', + method: 'get', + handler: async (req) => { + const url = new URL(req.url) + const query = url.searchParams.get('q') + const limit = parseInt(url.searchParams.get('limit') || '10') + + const results = await req.payload.find({ + collection: 'posts', + where: { + title: { + contains: query, + }, + }, + limit, + }) + + return Response.json(results) + }, +} +``` + +## CORS Headers + +```typescript +import { headersWithCors } from 'payload' + +export const corsEndpoint: Endpoint = { + path: '/public-data', + method: 'get', + handler: async (req) => { + const data = await fetchPublicData() + + return Response.json(data, { + headers: headersWithCors({ + headers: new Headers(), + req, + }), + }) + }, +} +``` + +## Error Handling + +```typescript +import { APIError } from 'payload' + +export const validateEndpoint: Endpoint = { + path: '/validate', + method: 'post', + handler: async (req) => { + const data = await req.json() + + if (!data.email) { + throw new APIError('Email is required', 400) + } + + return Response.json({ valid: true }) + }, +} +``` + +## Endpoint Placement + +### Collection Endpoints + +Mounted at `/api/{collection-slug}/{path}`. + +```typescript +export const Orders: CollectionConfig = { + slug: 'orders', + endpoints: [ + { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + // Available at: /api/orders/:id/tracking + const orderId = req.routeParams.id + return Response.json({ orderId }) + }, + }, + ], +} +``` + +### Global Endpoints + +Mounted at `/api/globals/{global-slug}/{path}`. + +```typescript +export const Settings: GlobalConfig = { + slug: 'settings', + endpoints: [ + { + path: '/clear-cache', + method: 'post', + handler: async (req) => { + // Available at: /api/globals/settings/clear-cache + await clearCache() + return Response.json({ message: 'Cache cleared' }) + }, + }, + ], +} +``` + +### Root Endpoints + +Mounted at `/api/{path}`. + +```typescript +export default buildConfig({ + endpoints: [ + { + path: '/hello', + method: 'get', + handler: () => { + // Available at: /api/hello + return Response.json({ message: 'Hello!' }) + }, + }, + ], +}) +``` + +## Best Practices + +1. **Always check authentication** - Custom endpoints are not authenticated by default +2. **Use `req.payload` for operations** - Ensures access control and hooks execute +3. **Use helpers for common tasks** - `addDataAndFileToRequest`, `headersWithCors` +4. **Throw `APIError` for errors** - Provides consistent error responses +5. **Return Web API `Response`** - Use `Response.json()` for consistent responses +6. **Validate input** - Check required fields, validate types +7. **Log errors** - Use `req.payload.logger` for debugging diff --git a/templates/with-postgres/.cursor/rules/field-type-guards.md b/templates/with-postgres/.cursor/rules/field-type-guards.md new file mode 100644 index 00000000000..3514ad44993 --- /dev/null +++ b/templates/with-postgres/.cursor/rules/field-type-guards.md @@ -0,0 +1,230 @@ +--- +title: Field Type Guards +description: Runtime field type checking and safe type narrowing +tags: [payload, typescript, type-guards, fields] +--- + +# Payload Field Type Guards + +Type guards for runtime field type checking and safe type narrowing. + +## Most Common Guards + +### fieldAffectsData + +**Most commonly used guard.** Checks if field stores data (has name and is not UI-only). + +```typescript +import { fieldAffectsData } from 'payload' + +function generateSchema(fields: Field[]) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + // Safe to access field.name + schema[field.name] = getFieldType(field) + } + }) +} + +// Filter data fields +const dataFields = fields.filter(fieldAffectsData) +``` + +### fieldHasSubFields + +Checks if field contains nested fields (group, array, row, or collapsible). + +```typescript +import { fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[]): void { + fields.forEach((field) => { + if (fieldHasSubFields(field)) { + // Safe to access field.fields + traverseFields(field.fields) + } + }) +} +``` + +### fieldIsArrayType + +Checks if field type is `'array'`. + +```typescript +import { fieldIsArrayType } from 'payload' + +if (fieldIsArrayType(field)) { + // field.type === 'array' + console.log(`Min rows: ${field.minRows}`) + console.log(`Max rows: ${field.maxRows}`) +} +``` + +## Capability Guards + +### fieldSupportsMany + +Checks if field can have multiple values (select, relationship, or upload with `hasMany`). + +```typescript +import { fieldSupportsMany } from 'payload' + +if (fieldSupportsMany(field)) { + // field.type is 'select' | 'relationship' | 'upload' + if (field.hasMany) { + console.log('Field accepts multiple values') + } +} +``` + +### fieldHasMaxDepth + +Checks if field is relationship/upload/join with numeric `maxDepth` property. + +```typescript +import { fieldHasMaxDepth } from 'payload' + +if (fieldHasMaxDepth(field)) { + // field.type is 'upload' | 'relationship' | 'join' + // AND field.maxDepth is number + const remainingDepth = field.maxDepth - currentDepth +} +``` + +### fieldIsVirtual + +Checks if field is virtual (computed or virtual relationship). + +```typescript +import { fieldIsVirtual } from 'payload' + +if (fieldIsVirtual(field)) { + // field.virtual is truthy + if (typeof field.virtual === 'string') { + console.log(`Virtual path: ${field.virtual}`) + } +} +``` + +## Type Checking Guards + +### fieldIsBlockType + +```typescript +import { fieldIsBlockType } from 'payload' + +if (fieldIsBlockType(field)) { + // field.type === 'blocks' + field.blocks.forEach((block) => { + console.log(`Block: ${block.slug}`) + }) +} +``` + +### fieldIsGroupType + +```typescript +import { fieldIsGroupType } from 'payload' + +if (fieldIsGroupType(field)) { + // field.type === 'group' + console.log(`Interface: ${field.interfaceName}`) +} +``` + +### fieldIsPresentationalOnly + +```typescript +import { fieldIsPresentationalOnly } from 'payload' + +if (fieldIsPresentationalOnly(field)) { + // field.type === 'ui' + // Skip in data operations, GraphQL schema, etc. + return +} +``` + +## Common Patterns + +### Recursive Field Traversal + +```typescript +import { fieldAffectsData, fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[], callback: (field: Field) => void) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + callback(field) + } + + if (fieldHasSubFields(field)) { + traverseFields(field.fields, callback) + } + }) +} +``` + +### Filter Data-Bearing Fields + +```typescript +import { fieldAffectsData, fieldIsPresentationalOnly, fieldIsHiddenOrDisabled } from 'payload' + +const dataFields = fields.filter( + (field) => + fieldAffectsData(field) && !fieldIsPresentationalOnly(field) && !fieldIsHiddenOrDisabled(field), +) +``` + +### Container Type Switching + +```typescript +import { fieldIsArrayType, fieldIsBlockType, fieldHasSubFields } from 'payload' + +if (fieldIsArrayType(field)) { + // Handle array-specific logic +} else if (fieldIsBlockType(field)) { + // Handle blocks-specific logic +} else if (fieldHasSubFields(field)) { + // Handle group/row/collapsible +} +``` + +### Safe Property Access + +```typescript +import { fieldSupportsMany, fieldHasMaxDepth } from 'payload' + +// With guard - safe access +if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') +} + +if (fieldHasMaxDepth(field)) { + const depth = field.maxDepth // TypeScript knows this is number +} +``` + +## All Available Guards + +| Type Guard | Checks For | Use When | +| --------------------------- | --------------------------------- | ---------------------------------------- | +| `fieldAffectsData` | Field stores data (has name) | Need to access field data or name | +| `fieldHasSubFields` | Field contains nested fields | Recursively traverse fields | +| `fieldIsArrayType` | Field is array type | Distinguish arrays from other containers | +| `fieldIsBlockType` | Field is blocks type | Handle blocks-specific logic | +| `fieldIsGroupType` | Field is group type | Handle group-specific logic | +| `fieldSupportsMany` | Field can have multiple values | Check for `hasMany` support | +| `fieldHasMaxDepth` | Field supports depth control | Control relationship/upload/join depth | +| `fieldIsPresentationalOnly` | Field is UI-only | Exclude from data operations | +| `fieldIsSidebar` | Field positioned in sidebar | Separate sidebar rendering | +| `fieldIsID` | Field name is 'id' | Special ID field handling | +| `fieldIsHiddenOrDisabled` | Field is hidden or disabled | Filter from UI operations | +| `fieldShouldBeLocalized` | Field needs localization | Proper locale table checks | +| `fieldIsVirtual` | Field is virtual | Skip in database transforms | +| `tabHasName` | Tab is named (stores data) | Distinguish named vs unnamed tabs | +| `groupHasName` | Group is named (stores data) | Distinguish named vs unnamed groups | +| `optionIsObject` | Option is `{label, value}` | Access option properties safely | +| `optionsAreObjects` | All options are objects | Batch option processing | +| `optionIsValue` | Option is string value | Handle string options | +| `valueIsValueWithRelation` | Value is polymorphic relationship | Handle polymorphic relationships | diff --git a/templates/with-postgres/.cursor/rules/fields.md b/templates/with-postgres/.cursor/rules/fields.md new file mode 100644 index 00000000000..8468e41f599 --- /dev/null +++ b/templates/with-postgres/.cursor/rules/fields.md @@ -0,0 +1,317 @@ +--- +title: Fields +description: Field types, patterns, and configurations +tags: [payload, fields, validation, conditional] +--- + +# Payload CMS Fields + +## Common Field Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## Field Types + +### Text Field + +```typescript +{ + name: 'title', + type: 'text', + required: true, + unique: true, + minLength: 5, + maxLength: 100, + index: true, + localized: true, + defaultValue: 'Default Title', + validate: (value) => Boolean(value) || 'Required', + admin: { + placeholder: 'Enter title...', + position: 'sidebar', + condition: (data) => data.showTitle === true, + }, +} +``` + +### Rich Text (Lexical) + +```typescript +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { HeadingFeature, LinkFeature } from '@payloadcms/richtext-lexical' + +{ + name: 'content', + type: 'richText', + required: true, + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + HeadingFeature({ + enabledHeadingSizes: ['h1', 'h2', 'h3'], + }), + LinkFeature({ + enabledCollections: ['posts', 'pages'], + }), + ], + }), +} +``` + +### Relationship + +```typescript +// Single relationship +{ + name: 'author', + type: 'relationship', + relationTo: 'users', + required: true, + maxDepth: 2, +} + +// Multiple relationships (hasMany) +{ + name: 'categories', + type: 'relationship', + relationTo: 'categories', + hasMany: true, + filterOptions: { + active: { equals: true }, + }, +} + +// Polymorphic relationship +{ + name: 'relatedContent', + type: 'relationship', + relationTo: ['posts', 'pages'], + hasMany: true, +} +``` + +### Array + +```typescript +{ + name: 'slides', + type: 'array', + minRows: 2, + maxRows: 10, + labels: { + singular: 'Slide', + plural: 'Slides', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'image', + type: 'upload', + relationTo: 'media', + }, + ], + admin: { + initCollapsed: true, + }, +} +``` + +### Blocks + +```typescript +import type { Block } from 'payload' + +const HeroBlock: Block = { + slug: 'hero', + interfaceName: 'HeroBlock', + fields: [ + { + name: 'heading', + type: 'text', + required: true, + }, + { + name: 'background', + type: 'upload', + relationTo: 'media', + }, + ], +} + +const ContentBlock: Block = { + slug: 'content', + fields: [ + { + name: 'text', + type: 'richText', + }, + ], +} + +{ + name: 'layout', + type: 'blocks', + blocks: [HeroBlock, ContentBlock], +} +``` + +### Select + +```typescript +{ + name: 'status', + type: 'select', + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + ], + defaultValue: 'draft', + required: true, +} + +// Multiple select +{ + name: 'tags', + type: 'select', + hasMany: true, + options: ['tech', 'news', 'sports'], +} +``` + +### Upload + +```typescript +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + required: true, + filterOptions: { + mimeType: { contains: 'image' }, + }, +} +``` + +### Point (Geolocation) + +```typescript +{ + name: 'location', + type: 'point', + label: 'Location', + required: true, +} + +// Query by distance +const nearbyLocations = await payload.find({ + collection: 'stores', + where: { + location: { + near: [10, 20], // [longitude, latitude] + maxDistance: 5000, // in meters + minDistance: 1000, + }, + }, +}) +``` + +### Join Fields (Reverse Relationships) + +```typescript +// From Users collection - show user's orders +{ + name: 'orders', + type: 'join', + collection: 'orders', + on: 'customer', // The field in 'orders' that references this user +} +``` + +### Tabs & Groups + +```typescript +// Tabs +{ + type: 'tabs', + tabs: [ + { + label: 'Content', + fields: [ + { name: 'title', type: 'text' }, + { name: 'body', type: 'richText' }, + ], + }, + { + label: 'SEO', + fields: [ + { name: 'metaTitle', type: 'text' }, + { name: 'metaDescription', type: 'textarea' }, + ], + }, + ], +} + +// Group (named) +{ + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], +} +``` + +## Validation + +```typescript +{ + name: 'email', + type: 'email', + validate: (value, { operation, data, siblingData }) => { + if (operation === 'create' && !value) { + return 'Email is required' + } + if (value && !value.includes('@')) { + return 'Invalid email format' + } + return true + }, +} +``` diff --git a/templates/with-postgres/.cursor/rules/hooks.md b/templates/with-postgres/.cursor/rules/hooks.md new file mode 100644 index 00000000000..1f168f9eaeb --- /dev/null +++ b/templates/with-postgres/.cursor/rules/hooks.md @@ -0,0 +1,175 @@ +--- +title: Hooks +description: Collection hooks, field hooks, and context patterns +tags: [payload, hooks, lifecycle, context] +--- + +# Payload CMS Hooks + +## Collection Hooks + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Field Hooks + +```typescript +import type { FieldHook } from 'payload' + +const beforeValidateHook: FieldHook = ({ value }) => { + return value.trim().toLowerCase() +} + +const afterReadHook: FieldHook = ({ value, req }) => { + // Hide email from non-admins + if (!req.user?.roles?.includes('admin')) { + return value.replace(/(.{2})(.*)(@.*)/, '$1***$3') + } + return value +} + +{ + name: 'email', + type: 'email', + hooks: { + beforeValidate: [beforeValidateHook], + afterRead: [afterReadHook], + }, +} +``` + +## Hook Context + +Share data between hooks or control hook behavior using request context: + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + beforeChange: [ + async ({ context }) => { + context.expensiveData = await fetchExpensiveData() + }, + ], + afterChange: [ + async ({ context, doc }) => { + // Reuse from previous hook + await processData(doc, context.expensiveData) + }, + ], + }, +} +``` + +## Next.js Revalidation Pattern + +```typescript +import type { CollectionAfterChangeHook } from 'payload' +import { revalidatePath } from 'next/cache' + +export const revalidatePage: CollectionAfterChangeHook = ({ + doc, + previousDoc, + req: { payload, context }, +}) => { + if (!context.disableRevalidate) { + if (doc._status === 'published') { + const path = doc.slug === 'home' ? '/' : `/${doc.slug}` + payload.logger.info(`Revalidating page at path: ${path}`) + revalidatePath(path) + } + + // Revalidate old path if unpublished + if (previousDoc?._status === 'published' && doc._status !== 'published') { + const oldPath = previousDoc.slug === 'home' ? '/' : `/${previousDoc.slug}` + revalidatePath(oldPath) + } + } + return doc +} +``` + +## Date Field Auto-Set + +```typescript +{ + name: 'publishedOn', + type: 'date', + hooks: { + beforeChange: [ + ({ siblingData, value }) => { + if (siblingData._status === 'published' && !value) { + return new Date() + } + return value + }, + ], + }, +} +``` + +## Best Practices + +- Use `beforeValidate` for data formatting +- Use `beforeChange` for business logic +- Use `afterChange` for side effects +- Use `afterRead` for computed fields +- Store expensive operations in `context` +- Pass `req` to nested operations for transaction safety +- Use context flags to prevent infinite loops diff --git a/templates/with-postgres/.cursor/rules/payload-overview.md b/templates/with-postgres/.cursor/rules/payload-overview.md new file mode 100644 index 00000000000..290c47822ab --- /dev/null +++ b/templates/with-postgres/.cursor/rules/payload-overview.md @@ -0,0 +1,126 @@ +--- +title: Payload CMS Overview +description: Core principles and quick reference for Payload CMS development +tags: [payload, overview, quickstart] +--- + +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Quick Reference + +| Task | Solution | +| --------------------- | ---------------------------------- | +| Auto-generate slugs | `slugField()` | +| Restrict by user | Access control with query | +| Local API user ops | `user` + `overrideAccess: false` | +| Draft/publish | `versions: { drafts: true }` | +| Computed fields | `virtual: true` with afterRead | +| Conditional fields | `admin.condition` | +| Custom validation | `validate` function | +| Filter relationships | `filterOptions` on field | +| Select fields | `select` parameter | +| Auto-set dates | beforeChange hook | +| Prevent loops | `req.context` check | +| Cascading deletes | beforeDelete hook | +| Geospatial queries | `point` field with `near`/`within` | +| Reverse relationships | `join` field type | +| Query relationships | Nested property syntax | +| Complex queries | AND/OR logic | +| Transactions | Pass `req` to operations | +| Background jobs | Jobs queue with tasks | +| Custom routes | Collection custom endpoints | +| Cloud storage | Storage adapter plugins | +| Multi-language | `localization` + `localized: true` | + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/with-postgres/.cursor/rules/plugin-development.md b/templates/with-postgres/.cursor/rules/plugin-development.md new file mode 100644 index 00000000000..d92bb12fb40 --- /dev/null +++ b/templates/with-postgres/.cursor/rules/plugin-development.md @@ -0,0 +1,323 @@ +--- +title: Plugin Development +description: Creating Payload CMS plugins with TypeScript patterns +tags: [payload, plugins, architecture, patterns] +--- + +# Payload Plugin Development + +## Plugin Architecture + +Plugins are functions that receive configuration options and return a function that transforms the Payload config: + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + enabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + // Transform config here + }) +``` + +**Key Pattern:** Double arrow function (currying) + +- First function: Accepts plugin options, returns plugin function +- Second function: Accepts Payload config, returns modified config + +## Adding Fields to Collections + +```typescript +export const seoPlugin = + (options: { collections?: string[] }): Plugin => + (config: Config): Config => { + const seoFields: Field[] = [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], + }, + ] + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...seoFields], + } + } + return collection + }), + } + } +``` + +## Adding New Collections + +```typescript +export const redirectsPlugin = + (options: { overrides?: Partial }): Plugin => + (config: Config): Config => { + const redirectsCollection: CollectionConfig = { + slug: 'redirects', + access: { read: () => true }, + fields: [ + { name: 'from', type: 'text', required: true, unique: true }, + { name: 'to', type: 'text', required: true }, + ], + ...options.overrides, + } + + return { + ...config, + collections: [...(config.collections || []), redirectsCollection], + } + } +``` + +## Adding Hooks + +```typescript +const resaveChildrenHook: CollectionAfterChangeHook = async ({ doc, req, operation }) => { + if (operation === 'update') { + const children = await req.payload.find({ + collection: 'pages', + where: { parent: { equals: doc.id } }, + }) + + for (const child of children.docs) { + await req.payload.update({ + collection: 'pages', + id: child.id, + data: child, + }) + } + } + return doc +} + +export const nestedDocsPlugin = + (options: { collections: string[] }): Plugin => + (config: Config): Config => ({ + ...config, + collections: (config.collections || []).map((collection) => { + if (options.collections.includes(collection.slug)) { + return { + ...collection, + hooks: { + ...(collection.hooks || {}), + afterChange: [resaveChildrenHook, ...(collection.hooks?.afterChange || [])], + }, + } + } + return collection + }), + }) +``` + +## Adding Root-Level Endpoints + +```typescript +export const seoPlugin = + (options: { generateTitle?: (doc: any) => string }): Plugin => + (config: Config): Config => { + const generateTitleEndpoint: Endpoint = { + path: '/plugin-seo/generate-title', + method: 'post', + handler: async (req) => { + const data = await req.json?.() + const result = options.generateTitle ? options.generateTitle(data.doc) : '' + return Response.json({ result }) + }, + } + + return { + ...config, + endpoints: [...(config.endpoints ?? []), generateTitleEndpoint], + } + } +``` + +## Field Overrides with Defaults + +```typescript +type FieldsOverride = (args: { defaultFields: Field[] }) => Field[] + +interface PluginConfig { + collections?: string[] + fields?: FieldsOverride +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const defaultFields: Field[] = [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ] + + const fields = + options.fields && typeof options.fields === 'function' + ? options.fields({ defaultFields }) + : defaultFields + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...fields], + } + } + return collection + }), + } + } +``` + +## Disable Plugin Pattern + +```typescript +interface PluginConfig { + disabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + // Always add collections/fields for database schema consistency + if (!config.collections) { + config.collections = [] + } + + config.collections.push({ + slug: 'plugin-collection', + fields: [{ name: 'title', type: 'text' }], + }) + + // If disabled, return early but keep schema changes + if (options.disabled) { + return config + } + + // Add endpoints, hooks, components only when enabled + config.endpoints = [ + ...(config.endpoints ?? []), + { + path: '/my-endpoint', + method: 'get', + handler: async () => Response.json({ message: 'Hello' }), + }, + ] + + return config + } +``` + +## Admin Components + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + if (!config.admin) config.admin = {} + if (!config.admin.components) config.admin.components = {} + if (!config.admin.components.beforeDashboard) { + config.admin.components.beforeDashboard = [] + } + + // Add client component + config.admin.components.beforeDashboard.push('my-plugin-name/client#BeforeDashboardClient') + + // Add server component (RSC) + config.admin.components.beforeDashboard.push('my-plugin-name/rsc#BeforeDashboardServer') + + return config + } +``` + +## onInit Hook + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const incomingOnInit = config.onInit + + config.onInit = async (payload) => { + // IMPORTANT: Call existing onInit first + if (incomingOnInit) await incomingOnInit(payload) + + // Plugin initialization + payload.logger.info('Plugin initialized') + + // Example: Seed data + const { totalDocs } = await payload.count({ + collection: 'plugin-collection', + where: { id: { equals: 'seeded-by-plugin' } }, + }) + + if (totalDocs === 0) { + await payload.create({ + collection: 'plugin-collection', + data: { id: 'seeded-by-plugin' }, + }) + } + } + + return config + } +``` + +## Best Practices + +### Preserve Existing Config + +```typescript +// ✅ Good +collections: [...(config.collections || []), newCollection] + +// ❌ Bad +collections: [newCollection] +``` + +### Respect User Overrides + +```typescript +const collection: CollectionConfig = { + slug: 'redirects', + fields: defaultFields, + ...options.overrides, // User overrides last +} +``` + +### Hook Composition + +```typescript +hooks: { + ...collection.hooks, + afterChange: [ + myHook, + ...(collection.hooks?.afterChange || []), + ], +} +``` + +### Type Safety + +```typescript +import type { Config, Plugin, CollectionConfig, Field } from 'payload' +``` diff --git a/templates/with-postgres/.cursor/rules/queries.md b/templates/with-postgres/.cursor/rules/queries.md new file mode 100644 index 00000000000..4920ec85f09 --- /dev/null +++ b/templates/with-postgres/.cursor/rules/queries.md @@ -0,0 +1,223 @@ +--- +title: Queries +description: Local API, REST, and GraphQL query patterns +tags: [payload, queries, local-api, rest, graphql] +--- + +# Payload CMS Queries + +## Query Operators + +```typescript +// Equals +{ color: { equals: 'blue' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater/less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In/not in +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (point fields) +{ location: { near: [10, 20, 5000] } } // [lng, lat, maxDistance] +``` + +## AND/OR Logic + +```typescript +{ + or: [ + { color: { equals: 'mint' } }, + { + and: [ + { color: { equals: 'white' } }, + { featured: { equals: false } }, + ], + }, + ], +} +``` + +## Nested Properties + +```typescript +{ + 'author.role': { equals: 'editor' }, + 'meta.featured': { exists: true }, +} +``` + +## Local API + +```typescript +// Find documents +const posts = await payload.find({ + collection: 'posts', + where: { + status: { equals: 'published' }, + 'author.name': { contains: 'john' }, + }, + depth: 2, // Populate relationships + limit: 10, + page: 1, + sort: '-createdAt', + locale: 'en', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const post = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { + status: 'published', + }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) + +// Count +const count = await payload.count({ + collection: 'posts', + where: { + status: { equals: 'published' }, + }, +}) +``` + +## Access Control in Local API + +**CRITICAL**: Local API bypasses access control by default (`overrideAccess: true`). + +```typescript +// ❌ WRONG: User is passed but access control is bypassed +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + // Result: Operation runs with ADMIN privileges +}) + +// ✅ CORRECT: Respects user's access control permissions +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + overrideAccess: false, // Required to enforce access control +}) + +// Administrative operation (intentionally bypass access control) +const allPosts = await payload.find({ + collection: 'posts', + // No user parameter, overrideAccess defaults to true +}) +``` + +**When to use `overrideAccess: false`:** + +- Performing operations on behalf of a user +- Testing access control logic +- API routes that should respect user permissions + +## REST API + +```typescript +import { stringify } from 'qs-esm' + +const query = { + status: { equals: 'published' }, +} + +const queryString = stringify( + { + where: query, + depth: 2, + limit: 10, + }, + { addQueryPrefix: true }, +) + +const response = await fetch(`https://api.example.com/api/posts${queryString}`) +const data = await response.json() +``` + +### REST Endpoints + +``` +GET /api/{collection} - Find documents +GET /api/{collection}/{id} - Find by ID +POST /api/{collection} - Create +PATCH /api/{collection}/{id} - Update +DELETE /api/{collection}/{id} - Delete +GET /api/{collection}/count - Count documents + +GET /api/globals/{slug} - Get global +POST /api/globals/{slug} - Update global +``` + +## GraphQL + +```graphql +query { + Posts(where: { status: { equals: published } }, limit: 10, sort: "-createdAt") { + docs { + id + title + author { + name + } + } + totalDocs + hasNextPage + } +} + +mutation { + createPost(data: { title: "New Post", status: draft }) { + id + title + } +} +``` + +## Performance Best Practices + +- Set `maxDepth` on relationships to prevent over-fetching +- Use `select` to limit returned fields +- Index frequently queried fields +- Use `virtual` fields for computed data +- Cache expensive operations in hook `context` diff --git a/templates/with-postgres/.cursor/rules/security-critical.mdc b/templates/with-postgres/.cursor/rules/security-critical.mdc new file mode 100644 index 00000000000..adf5d9e225d --- /dev/null +++ b/templates/with-postgres/.cursor/rules/security-critical.mdc @@ -0,0 +1,122 @@ +--- +title: Critical Security Patterns +description: The three most important security patterns in Payload CMS +tags: [payload, security, critical, access-control, transactions, hooks] +priority: high +--- + +# CRITICAL SECURITY PATTERNS + +These are the three most critical security patterns that MUST be followed in every Payload CMS project. + +## 1. Local API Access Control (MOST IMPORTANT) + +**By default, Local API operations bypass ALL access control**, even when passing a user. + +```typescript +// ❌ SECURITY BUG: Passes user but ignores their permissions +await payload.find({ + collection: 'posts', + user: someUser, // Access control is BYPASSED! +}) + +// ✅ SECURE: Actually enforces the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED for access control +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**When to use each:** + +- `overrideAccess: true` (default) - Server-side operations you trust (cron jobs, system tasks) +- `overrideAccess: false` - When operating on behalf of a user (API routes, webhooks) + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +## 2. Transaction Safety in Hooks + +**Nested operations in hooks without `req` break transaction atomicity.** + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ] +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ] +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +## 3. Prevent Infinite Hook Loops + +**Hooks triggering operations that trigger the same hooks create infinite loops.** + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ] +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ] +} +``` + +**Rule**: Use `req.context` flags to prevent hook loops diff --git a/templates/with-postgres/AGENTS.md b/templates/with-postgres/AGENTS.md new file mode 100644 index 00000000000..633b29b1f61 --- /dev/null +++ b/templates/with-postgres/AGENTS.md @@ -0,0 +1,1141 @@ +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default +6. **Access Control**: Ensure roles exist when modifiyng collection or globals with access controls + +### Code Validation + +- To validate typescript correctness after modifying code run `tsc --noEmit` +- Generate import maps after creating or modifying components. + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Configuration + +### Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Collections + +### Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +### Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Fields + +### Common Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## CRITICAL SECURITY PATTERNS + +### 1. Local API Access Control (MOST IMPORTANT) + +```typescript +// ❌ SECURITY BUG: Access control bypassed +await payload.find({ + collection: 'posts', + user: someUser, // Ignored! Operation runs with ADMIN privileges +}) + +// ✅ SECURE: Enforces user permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +### 2. Transaction Safety in Hooks + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ], +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ], +} +``` + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +### 3. Prevent Infinite Hook Loops + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ], +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ], +} +``` + +## Access Control + +### Collection-Level Access + +```typescript +import type { Access } from 'payload' + +// Boolean return +const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Query constraint (row-level security) +const ownPostsOnly: Access = ({ req: { user } }) => { + if (!user) return false + if (user?.roles?.includes('admin')) return true + + return { + author: { equals: user.id }, + } +} + +// Async access check +const projectMemberAccess: Access = async ({ req, id }) => { + const { user, payload } = req + + if (!user) return false + if (user.roles?.includes('admin')) return true + + const project = await payload.findByID({ + collection: 'projects', + id: id as string, + depth: 0, + }) + + return project.members?.includes(user.id) +} +``` + +### Field-Level Access + +```typescript +// Field access ONLY returns boolean (no query constraints) +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +### Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Hooks + +### Common Hook Patterns + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Queries + +### Local API + +```typescript +// Find with complex query +const posts = await payload.find({ + collection: 'posts', + where: { + and: [{ status: { equals: 'published' } }, { 'author.name': { contains: 'john' } }], + }, + depth: 2, // Populate relationships + limit: 10, + sort: '-createdAt', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const newPost = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { status: 'published' }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) +``` + +### Query Operators + +```typescript +// Equals +{ status: { equals: 'published' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater than / less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In array +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (geospatial) +{ location: { near: [-122.4194, 37.7749, 10000] } } +``` + +### AND/OR Logic + +```typescript +{ + or: [ + { status: { equals: 'published' } }, + { author: { equals: user.id } }, + ], +} + +{ + and: [ + { status: { equals: 'published' } }, + { featured: { equals: true } }, + ], +} +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Components + +The Admin Panel can be extensively customized using React Components. Custom Components can be Server Components (default) or Client Components. + +### Defining Components + +Components are defined using **file paths** (not direct imports) in your config: + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + // Logo and branding + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + + // Navigation + Nav: '/components/CustomNav', + beforeNavLinks: ['/components/CustomNavItem'], + afterNavLinks: ['/components/NavFooter'], + + // Header + header: ['/components/AnnouncementBanner'], + actions: ['/components/ClearCache', '/components/Preview'], + + // Dashboard + beforeDashboard: ['/components/WelcomeMessage'], + afterDashboard: ['/components/Analytics'], + + // Auth + beforeLogin: ['/components/SSOButtons'], + logout: { Button: '/components/LogoutButton' }, + + // Settings + settingsMenu: ['/components/SettingsMenu'], + + // Views + views: { + dashboard: { Component: '/components/CustomDashboard' }, + }, + }, + }, +}) +``` + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Server vs Client Components + +**All components are Server Components by default** (can use Local API directly): + +```tsx +// Server Component (default) +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const posts = await payload.find({ collection: 'posts' }) + return
{posts.totalDocs} posts
+} + +export default MyServerComponent +``` + +**Client Components** need the `'use client'` directive: + +```tsx +'use client' +import { useState } from 'react' +import { useAuth } from '@payloadcms/ui' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + const { user } = useAuth() + + return ( + + ) +} +``` + +### Using Hooks (Client Components Only) + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Document info (id, collection, etc.) + useField, // Field value and setter + useForm, // Form state + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +### Collection/Global Components + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/SaveDraft', + PublishButton: '/components/Publish', + }, + + // List view + list: { + Header: '/components/ListHeader', + beforeList: ['/components/BulkActions'], + afterList: ['/components/ListFooter'], + }, + }, + }, +} +``` + +### Field Components + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + // Edit view field + Field: '/components/StatusField', + // List view cell + Cell: '/components/StatusCell', + // Field label + Label: '/components/StatusLabel', + // Field description + Description: '/components/StatusDescription', + // Error message + Error: '/components/StatusError', + }, + }, +} +``` + +**UI Field** (presentational only, no data): + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +### Performance Best Practices + +1. **Import correctly:** + + - Admin Panel: `import { Button } from '@payloadcms/ui'` + - Frontend: `import { Button } from '@payloadcms/ui/elements/Button'` + +2. **Optimize re-renders:** + + ```tsx + // ❌ BAD: Re-renders on every form change + const { fields } = useForm() + + // ✅ GOOD: Only re-renders when specific field changes + const value = useFormFields(([fields]) => fields[path]) + ``` + +3. **Prefer Server Components** - Only use Client Components when you need: + + - State (useState, useReducer) + - Effects (useEffect) + - Event handlers (onClick, onChange) + - Browser APIs (localStorage, window) + +4. **Minimize serialized props** - Server Components serialize props sent to client + +### Styling Components + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Content
+} +``` + +```scss +// Use Payload's CSS variables +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} + +// Import Payload's SCSS library +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +### Type Safety + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, + SelectFieldServerComponent, + // ... etc +} from 'payload' + +export const MyField: TextFieldClientComponent = (props) => { + // Fully typed props +} +``` + +### Import Map + +Payload auto-generates `app/(payload)/admin/importMap.js` to resolve component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Set custom location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Custom Endpoints + +```typescript +import type { Endpoint } from 'payload' +import { APIError } from 'payload' + +// Always check authentication +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} + +// Route parameters +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Drafts & Versions + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} + +// Create draft +await payload.create({ + collection: 'pages', + data: { title: 'Draft Page' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft if available +}) +``` + +## Field Type Guards + +```typescript +import { + fieldAffectsData, + fieldHasSubFields, + fieldIsArrayType, + fieldIsBlockType, + fieldSupportsMany, + fieldHasMaxDepth, +} from 'payload' + +function processField(field: Field) { + // Check if field stores data + if (fieldAffectsData(field)) { + console.log(field.name) // Safe to access + } + + // Check if field has nested fields + if (fieldHasSubFields(field)) { + field.fields.forEach(processField) // Safe to access + } + + // Check field type + if (fieldIsArrayType(field)) { + console.log(field.minRows, field.maxRows) + } + + // Check capabilities + if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') + } +} +``` + +## Plugins + +### Using Plugins + +```typescript +import { seoPlugin } from '@payloadcms/plugin-seo' +import { redirectsPlugin } from '@payloadcms/plugin-redirects' + +export default buildConfig({ + plugins: [ + seoPlugin({ + collections: ['posts', 'pages'], + }), + redirectsPlugin({ + collections: ['pages'], + }), + ], +}) +``` + +### Creating Plugins + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + collections?: string[] + enabled?: boolean +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...collection.fields, { name: 'pluginField', type: 'text' }], + } + } + return collection + }), + }) +``` + +## Best Practices + +### Security + +1. Always set `overrideAccess: false` when passing `user` to Local API +2. Field-level access only returns boolean (no query constraints) +3. Default to restrictive access, gradually add permissions +4. Never trust client-provided data +5. Use `saveToJWT: true` for roles to avoid database lookups + +### Performance + +1. Index frequently queried fields +2. Use `select` to limit returned fields +3. Set `maxDepth` on relationships to prevent over-fetching +4. Use query constraints over async operations in access control +5. Cache expensive operations in `req.context` + +### Data Integrity + +1. Always pass `req` to nested operations in hooks +2. Use context flags to prevent infinite hook loops +3. Enable transactions for MongoDB (requires replica set) and Postgres +4. Use `beforeValidate` for data formatting +5. Use `beforeChange` for business logic + +### Type Safety + +1. Run `generate:types` after schema changes +2. Import types from generated `payload-types.ts` +3. Type your user object: `import type { User } from '@/payload-types'` +4. Use `as const` for field options +5. Use field type guards for runtime type checking + +### Organization + +1. Keep collections in separate files +2. Extract access control to `access/` directory +3. Extract hooks to `hooks/` directory +4. Use reusable field factories for common patterns +5. Document complex access control with comments + +## Common Gotchas + +1. **Local API Default**: Access control bypassed unless `overrideAccess: false` +2. **Transaction Safety**: Missing `req` in nested operations breaks atomicity +3. **Hook Loops**: Operations in hooks can trigger the same hooks +4. **Field Access**: Cannot use query constraints, only boolean +5. **Relationship Depth**: Default depth is 2, set to 0 for IDs only +6. **Draft Status**: `_status` field auto-injected when drafts enabled +7. **Type Generation**: Types not updated until `generate:types` runs +8. **MongoDB Transactions**: Require replica set configuration +9. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +10. **Point Fields**: Not supported in SQLite + +## Additional Context Files + +For deeper exploration of specific topics, refer to the context files located in `.cursor/rules/`: + +### Available Context Files + +1. **`payload-overview.md`** - High-level architecture and core concepts + + - Payload structure and initialization + - Configuration fundamentals + - Database adapters overview + +2. **`security-critical.md`** - Critical security patterns (⚠️ IMPORTANT) + + - Local API access control + - Transaction safety in hooks + - Preventing infinite hook loops + +3. **`collections.md`** - Collection configurations + + - Basic collection patterns + - Auth collections with RBAC + - Upload collections + - Drafts and versioning + - Globals + +4. **`fields.md`** - Field types and patterns + + - All field types with examples + - Conditional fields + - Virtual fields + - Field validation + - Common field patterns + +5. **`field-type-guards.md`** - TypeScript field type utilities + + - Field type checking utilities + - Safe type narrowing + - Runtime field validation + +6. **`access-control.md`** - Permission patterns + + - Collection-level access + - Field-level access + - Row-level security + - RBAC patterns + - Multi-tenant access control + +7. **`access-control-advanced.md`** - Complex access patterns + + - Nested document access + - Cross-collection permissions + - Dynamic role hierarchies + - Performance optimization + +8. **`hooks.md`** - Lifecycle hooks + + - Collection hooks + - Field hooks + - Hook context patterns + - Common hook recipes + +9. **`queries.md`** - Database operations + + - Local API usage + - Query operators + - Complex queries with AND/OR + - Performance optimization + +10. **`endpoints.md`** - Custom API endpoints + + - REST endpoint patterns + - Authentication in endpoints + - Error handling + - Route parameters + +11. **`adapters.md`** - Database and storage adapters + + - MongoDB, PostgreSQL, SQLite patterns + - Storage adapter usage (S3, Azure, GCS, etc.) + - Custom adapter development + +12. **`plugin-development.md`** - Creating plugins + + - Plugin architecture + - Modifying configuration + - Plugin hooks + - Best practices + +13. **`components.md`** - Custom Components + + - Component types (Root, Collection, Global, Field) + - Server vs Client Components + - Component paths and definition + - Default and custom props + - Using hooks + - Performance best practices + - Styling components + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/with-postgres/package.json b/templates/with-postgres/package.json index 69e022dd539..86d822a7142 100644 --- a/templates/with-postgres/package.json +++ b/templates/with-postgres/package.json @@ -19,14 +19,14 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/db-postgres": "3.63.0", - "@payloadcms/next": "3.63.0", - "@payloadcms/richtext-lexical": "3.63.0", - "@payloadcms/ui": "3.63.0", + "@payloadcms/db-postgres": "3.68.5", + "@payloadcms/next": "3.68.5", + "@payloadcms/richtext-lexical": "3.68.5", + "@payloadcms/ui": "3.68.5", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.63.0", + "payload": "3.68.5", "react": "19.2.1", "react-dom": "19.2.1", "sharp": "0.34.2" diff --git a/templates/with-postgres/src/migrations/20251107_183854_initial.json b/templates/with-postgres/src/migrations/20251216_194340_initial.json similarity index 99% rename from templates/with-postgres/src/migrations/20251107_183854_initial.json rename to templates/with-postgres/src/migrations/20251216_194340_initial.json index 347366f6a0a..3fa5791b871 100644 --- a/templates/with-postgres/src/migrations/20251107_183854_initial.json +++ b/templates/with-postgres/src/migrations/20251216_194340_initial.json @@ -1,6 +1,4 @@ { - "id": "255dcb47-65ad-46bd-9bd7-6d5581478a90", - "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", "tables": { @@ -935,5 +933,7 @@ "schemas": {}, "tables": {}, "columns": {} - } + }, + "id": "0feee724-64cb-470b-ba33-0c37b438502a", + "prevId": "00000000-0000-0000-0000-000000000000" } diff --git a/templates/with-postgres/src/migrations/20251107_183854_initial.ts b/templates/with-postgres/src/migrations/20251216_194340_initial.ts similarity index 100% rename from templates/with-postgres/src/migrations/20251107_183854_initial.ts rename to templates/with-postgres/src/migrations/20251216_194340_initial.ts diff --git a/templates/with-postgres/src/migrations/index.ts b/templates/with-postgres/src/migrations/index.ts index c77a1bf1a57..2bbf53e80d0 100644 --- a/templates/with-postgres/src/migrations/index.ts +++ b/templates/with-postgres/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20251107_183854_initial from './20251107_183854_initial' +import * as migration_20251216_194340_initial from './20251216_194340_initial' export const migrations = [ { - up: migration_20251107_183854_initial.up, - down: migration_20251107_183854_initial.down, - name: '20251107_183854_initial', + up: migration_20251216_194340_initial.up, + down: migration_20251216_194340_initial.down, + name: '20251216_194340_initial', }, ] diff --git a/templates/with-postgres/src/payload-types.ts b/templates/with-postgres/src/payload-types.ts index 0d481af819e..4133934a069 100644 --- a/templates/with-postgres/src/payload-types.ts +++ b/templates/with-postgres/src/payload-types.ts @@ -86,6 +86,7 @@ export interface Config { db: { defaultIDType: number; }; + fallbackLocale: null; globals: {}; globalsSelect: {}; locale: null; diff --git a/templates/with-vercel-mongodb/.cursor/rules/access-control-advanced.md b/templates/with-vercel-mongodb/.cursor/rules/access-control-advanced.md new file mode 100644 index 00000000000..68f52fd1287 --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/access-control-advanced.md @@ -0,0 +1,519 @@ +--- +title: Access Control - Advanced Patterns +description: Context-aware, time-based, subscription-based access, factory functions, templates +tags: [payload, access-control, security, advanced, performance] +priority: high +--- + +# Advanced Access Control Patterns + +Advanced access control patterns including context-aware access, time-based restrictions, factory functions, and production templates. + +## Context-Aware Access Patterns + +### Locale-Specific Access + +```typescript +import type { Access } from 'payload' + +export const localeSpecificAccess: Access = ({ req: { user, locale } }) => { + // Authenticated users can access all locales + if (user) return true + + // Public users can only access English content + if (locale === 'en') return true + + return false +} +``` + +### Device-Specific Access + +```typescript +export const mobileOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return /mobile|android|iphone/i.test(userAgent) +} + +export const desktopOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return !/mobile|android|iphone/i.test(userAgent) +} +``` + +### IP-Based Access + +```typescript +export const restrictedIpAccess = (allowedIps: string[]): Access => { + return ({ req: { headers } }) => { + const ip = headers?.get('x-forwarded-for') || headers?.get('x-real-ip') + return allowedIps.includes(ip || '') + } +} + +// Usage +const internalIps = ['192.168.1.0/24', '10.0.0.5'] + +export const InternalDocs: CollectionConfig = { + slug: 'internal-docs', + access: { + read: restrictedIpAccess(internalIps), + }, +} +``` + +## Time-Based Access Patterns + +### Today's Records Only + +```typescript +export const todayOnlyAccess: Access = ({ req: { user } }) => { + if (!user) return false + + const now = new Date() + const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000) + + return { + createdAt: { + greater_than_equal: startOfDay.toISOString(), + less_than: endOfDay.toISOString(), + }, + } +} +``` + +### Recent Records (Last N Days) + +```typescript +export const recentRecordsAccess = (days: number): Access => { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - days) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} + +// Usage: Users see only last 30 days, admins see all +export const Logs: CollectionConfig = { + slug: 'logs', + access: { + read: recentRecordsAccess(30), + }, +} +``` + +### Scheduled Content (Publish Date Range) + +```typescript +export const scheduledContentAccess: Access = ({ req: { user } }) => { + // Editors see all content + if (user?.roles?.includes('admin') || user?.roles?.includes('editor')) { + return true + } + + const now = new Date().toISOString() + + // Public sees only content within publish window + return { + and: [ + { publishDate: { less_than_equal: now } }, + { + or: [{ unpublishDate: { exists: false } }, { unpublishDate: { greater_than: now } }], + }, + ], + } +} +``` + +## Subscription-Based Access + +### Active Subscription Required + +```typescript +export const activeSubscriptionAccess: Access = async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + return subscription?.status === 'active' + } catch { + return false + } +} +``` + +### Subscription Tier-Based Access + +```typescript +export const tierBasedAccess = (requiredTier: string): Access => { + const tierHierarchy = ['free', 'basic', 'pro', 'enterprise'] + + return async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + if (subscription?.status !== 'active') return false + + const userTierIndex = tierHierarchy.indexOf(subscription.tier) + const requiredTierIndex = tierHierarchy.indexOf(requiredTier) + + return userTierIndex >= requiredTierIndex + } catch { + return false + } + } +} + +// Usage +export const EnterpriseFeatures: CollectionConfig = { + slug: 'enterprise-features', + access: { + read: tierBasedAccess('enterprise'), + }, +} +``` + +## Factory Functions + +### createRoleBasedAccess + +```typescript +export function createRoleBasedAccess(roles: string[]): Access { + return ({ req: { user } }) => { + if (!user) return false + return roles.some((role) => user.roles?.includes(role)) + } +} + +// Usage +const adminOrEditor = createRoleBasedAccess(['admin', 'editor']) +const moderatorAccess = createRoleBasedAccess(['admin', 'moderator']) +``` + +### createOrgScopedAccess + +```typescript +export function createOrgScopedAccess(allowAdmin = true): Access { + return ({ req: { user } }) => { + if (!user) return false + if (allowAdmin && user.roles?.includes('admin')) return true + + return { + organizationId: { in: user.organizationIds || [] }, + } + } +} + +// Usage +const orgScoped = createOrgScopedAccess() // Admins bypass +const strictOrgScoped = createOrgScopedAccess(false) // Admins also scoped +``` + +### createTeamBasedAccess + +```typescript +export function createTeamBasedAccess(teamField = 'teamId'): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + [teamField]: { in: user.teamIds || [] }, + } + } +} +``` + +### createTimeLimitedAccess + +```typescript +export function createTimeLimitedAccess(daysAccess: number): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - daysAccess) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} +``` + +## Configuration Templates + +### Public + Authenticated Collection + +```typescript +export const PublicAuthCollection: CollectionConfig = { + slug: 'posts', + access: { + // Only admins/editors can create + create: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Authenticated users see all, public sees only published + read: ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } + }, + + // Only admins/editors can update + update: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Only admins can delete + delete: ({ req: { user } }) => { + return user?.roles?.includes('admin') || false + }, + }, + versions: { + drafts: true, + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'content', type: 'richText', required: true }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], +} +``` + +### Self-Service Collection + +```typescript +export const SelfServiceCollection: CollectionConfig = { + slug: 'users', + auth: true, + access: { + // Admins can create users + create: ({ req: { user } }) => user?.roles?.includes('admin') || false, + + // Anyone can read user profiles + read: () => true, + + // Users can update self, admins can update anyone + update: ({ req: { user }, id }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + return user.id === id + }, + + // Only admins can delete + delete: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + fields: [ + { name: 'name', type: 'text', required: true }, + { name: 'email', type: 'email', required: true }, + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + access: { + // Only admins can read/update roles + read: ({ req: { user } }) => user?.roles?.includes('admin') || false, + update: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + }, + ], +} +``` + +## Performance Considerations + +### Avoid Async Operations in Hot Paths + +```typescript +// ❌ Slow: Multiple sequential async calls +export const slowAccess: Access = async ({ req: { user } }) => { + const org = await req.payload.findByID({ collection: 'orgs', id: user.orgId }) + const team = await req.payload.findByID({ collection: 'teams', id: user.teamId }) + const subscription = await req.payload.findByID({ collection: 'subs', id: user.subId }) + + return org.active && team.active && subscription.active +} + +// ✅ Fast: Use query constraints or cache in context +export const fastAccess: Access = ({ req: { user, context } }) => { + // Cache expensive lookups + if (!context.orgStatus) { + context.orgStatus = checkOrgStatus(user.orgId) + } + + return context.orgStatus +} +``` + +### Query Constraint Optimization + +```typescript +// ❌ Avoid: Non-indexed fields in constraints +export const slowQuery: Access = () => ({ + 'metadata.internalCode': { equals: 'ABC123' }, // Slow if not indexed +}) + +// ✅ Better: Use indexed fields +export const fastQuery: Access = () => ({ + status: { equals: 'active' }, // Indexed field + organizationId: { in: ['org1', 'org2'] }, // Indexed field +}) +``` + +### Field Access on Large Arrays + +```typescript +// ❌ Slow: Complex access on array fields +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: async ({ req }) => { + // Async call runs for EVERY array item + const result = await expensiveCheck() + return result + }, + }, + }, + ], +} + +// ✅ Fast: Simple checks or cache result +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: ({ req: { user }, context }) => { + // Cache once, reuse for all items + if (context.canReadSecret === undefined) { + context.canReadSecret = user?.roles?.includes('admin') + } + return context.canReadSecret + }, + }, + }, + ], +} +``` + +### Avoid N+1 Queries + +```typescript +// ❌ N+1 Problem: Query per access check +export const n1Access: Access = async ({ req, id }) => { + // Runs for EACH document in list + const doc = await req.payload.findByID({ collection: 'docs', id }) + return doc.isPublic +} + +// ✅ Better: Use query constraint to filter at DB level +export const efficientAccess: Access = () => { + return { isPublic: { equals: true } } +} +``` + +## Debugging Tips + +### Log Access Check Execution + +```typescript +export const debugAccess: Access = ({ req: { user }, id }) => { + console.log('Access check:', { + userId: user?.id, + userRoles: user?.roles, + docId: id, + timestamp: new Date().toISOString(), + }) + return true +} +``` + +### Verify Arguments Availability + +```typescript +export const checkArgsAccess: Access = (args) => { + console.log('Available arguments:', { + hasReq: 'req' in args, + hasUser: args.req?.user ? 'yes' : 'no', + hasId: args.id ? 'provided' : 'undefined', + hasData: args.data ? 'provided' : 'undefined', + }) + return true +} +``` + +### Test Access Without User + +```typescript +// In test/development +const testAccess = await payload.find({ + collection: 'posts', + overrideAccess: false, // Enforce access control + user: undefined, // Simulate no user +}) + +console.log('Public access result:', testAccess.docs.length) +``` + +## Best Practices + +1. **Default Deny**: Start with restrictive access, gradually add permissions +2. **Type Guards**: Use TypeScript for user type safety +3. **Validate Data**: Never trust frontend-provided IDs or data +4. **Async for Critical Checks**: Use async operations for important security decisions +5. **Consistent Logic**: Apply same rules at field and collection levels +6. **Test Edge Cases**: Test with no user, wrong user, admin user scenarios +7. **Monitor Access**: Log failed access attempts for security review +8. **Regular Audit**: Review access rules quarterly or after major changes +9. **Cache Wisely**: Use `req.context` for expensive operations +10. **Document Intent**: Add comments explaining complex access rules +11. **Avoid Secrets in Client**: Never expose sensitive logic to client-side +12. **Handle Errors Gracefully**: Access functions should return `false` on error, not throw +13. **Test Local API**: Remember to set `overrideAccess: false` when testing +14. **Consider Performance**: Measure impact of async operations +15. **Principle of Least Privilege**: Grant minimum access required + +## Performance Summary + +**Minimize Async Operations**: Use query constraints over async lookups when possible + +**Cache Expensive Checks**: Store results in `req.context` for reuse + +**Index Query Fields**: Ensure fields in query constraints are indexed + +**Avoid Complex Logic in Array Fields**: Simple boolean checks preferred + +**Use Query Constraints**: Let database filter rather than loading all records diff --git a/templates/with-vercel-mongodb/.cursor/rules/access-control.md b/templates/with-vercel-mongodb/.cursor/rules/access-control.md new file mode 100644 index 00000000000..7b9a0a4ba5c --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/access-control.md @@ -0,0 +1,225 @@ +--- +title: Access Control +description: Collection, field, and global access control patterns +tags: [payload, access-control, security, permissions, rbac] +--- + +# Payload CMS Access Control + +## Access Control Layers + +1. **Collection-Level**: Controls operations on entire documents (create, read, update, delete, admin) +2. **Field-Level**: Controls access to individual fields (create, read, update) +3. **Global-Level**: Controls access to global documents (read, update) + +## Collection Access Control + +```typescript +import type { Access } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + // Boolean: Only authenticated users can create + create: ({ req: { user } }) => Boolean(user), + + // Query constraint: Public sees published, users see all + read: ({ req: { user } }) => { + if (user) return true + return { status: { equals: 'published' } } + }, + + // User-specific: Admins or document owner + update: ({ req: { user }, id }) => { + if (user?.roles?.includes('admin')) return true + return { author: { equals: user?.id } } + }, + + // Async: Check related data + delete: async ({ req, id }) => { + const hasComments = await req.payload.count({ + collection: 'comments', + where: { post: { equals: id } }, + }) + return hasComments === 0 + }, + }, +} +``` + +## Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Row-Level Security + +```typescript +// Organization-scoped access +export const organizationScoped: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + + // Users see only their organization's data + return { + organization: { + equals: user?.organization, + }, + } +} + +// Team-based access +export const teamMemberAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + 'team.members': { + contains: user.id, + }, + } +} +``` + +## Field Access Control + +**Field access ONLY returns boolean** (no query constraints). + +```typescript +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +## RBAC Pattern + +Payload does NOT provide a roles system by default. Add a `roles` field to your auth collection: + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Multi-Tenant Access Control + +```typescript +interface User { + id: string + tenantId: string + roles?: string[] +} + +const tenantAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('super-admin')) return true + + return { + tenant: { + equals: (user as User).tenantId, + }, + } +} + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + create: tenantAccess, + read: tenantAccess, + update: tenantAccess, + delete: tenantAccess, + }, + fields: [ + { + name: 'tenant', + type: 'text', + required: true, + access: { + update: ({ req: { user } }) => user?.roles?.includes('super-admin'), + }, + hooks: { + beforeChange: [ + ({ req, operation, value }) => { + if (operation === 'create' && !value) { + return (req.user as User)?.tenantId + } + return value + }, + ], + }, + }, + ], +} +``` + +## Important Notes + +1. **Local API Default**: Access control is **skipped by default** in Local API (`overrideAccess: true`). When passing a `user` parameter, you must set `overrideAccess: false`: + +```typescript +// ❌ WRONG: Passes user but bypasses access control +await payload.find({ + collection: 'posts', + user: someUser, +}) + +// ✅ CORRECT: Respects the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // Required to enforce access control +}) +``` + +2. **Field Access Limitations**: Field-level access does NOT support query constraints - only boolean returns. + +3. **Admin Panel Visibility**: The `admin` access control determines if a collection appears in the admin panel for a user. diff --git a/templates/with-vercel-mongodb/.cursor/rules/adapters.md b/templates/with-vercel-mongodb/.cursor/rules/adapters.md new file mode 100644 index 00000000000..49b8b3367fc --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/adapters.md @@ -0,0 +1,209 @@ +--- +title: Database Adapters & Transactions +description: Database adapters, storage, email, and transaction patterns +tags: [payload, database, mongodb, postgres, sqlite, transactions] +--- + +# Payload CMS Adapters + +## Database Adapters + +### MongoDB + +```typescript +import { mongooseAdapter } from '@payloadcms/db-mongodb' + +export default buildConfig({ + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +### Postgres + +```typescript +import { postgresAdapter } from '@payloadcms/db-postgres' + +export default buildConfig({ + db: postgresAdapter({ + pool: { + connectionString: process.env.DATABASE_URI, + }, + push: false, // Don't auto-push schema changes + migrationDir: './migrations', + }), +}) +``` + +### SQLite + +```typescript +import { sqliteAdapter } from '@payloadcms/db-sqlite' + +export default buildConfig({ + db: sqliteAdapter({ + client: { + url: 'file:./payload.db', + }, + transactionOptions: {}, // Enable transactions (disabled by default) + }), +}) +``` + +## Transactions + +Payload automatically uses transactions for all-or-nothing database operations. + +### Threading req Through Operations + +**CRITICAL**: When performing nested operations in hooks, always pass `req` to maintain transaction context. + +```typescript +// ✅ CORRECT: Thread req through nested operations +const resaveChildren: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + // Find children - pass req + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + req, // Maintains transaction context + }) + + // Update each child - pass req + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + req, // Same transaction as parent operation + }) + } +} + +// ❌ WRONG: Missing req breaks transaction +const brokenHook: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + // Missing req - separate transaction or no transaction + }) + + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + // Missing req - if parent operation fails, these updates persist + }) + } +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +### Manual Transaction Control + +```typescript +const transactionID = await payload.db.beginTransaction() +try { + await payload.create({ + collection: 'orders', + data: orderData, + req: { transactionID }, + }) + await payload.update({ + collection: 'inventory', + id: itemId, + data: { stock: newStock }, + req: { transactionID }, + }) + await payload.db.commitTransaction(transactionID) +} catch (error) { + await payload.db.rollbackTransaction(transactionID) + throw error +} +``` + +## Storage Adapters + +Available storage adapters: + +- **@payloadcms/storage-s3** - AWS S3 +- **@payloadcms/storage-azure** - Azure Blob Storage +- **@payloadcms/storage-gcs** - Google Cloud Storage +- **@payloadcms/storage-r2** - Cloudflare R2 +- **@payloadcms/storage-vercel-blob** - Vercel Blob +- **@payloadcms/storage-uploadthing** - Uploadthing + +### AWS S3 + +```typescript +import { s3Storage } from '@payloadcms/storage-s3' + +export default buildConfig({ + plugins: [ + s3Storage({ + collections: { + media: true, + }, + bucket: process.env.S3_BUCKET, + config: { + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + region: process.env.S3_REGION, + }, + }), + ], +}) +``` + +## Email Adapters + +### Nodemailer (SMTP) + +```typescript +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' + +export default buildConfig({ + email: nodemailerAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + transportOptions: { + host: process.env.SMTP_HOST, + port: 587, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }, + }), +}) +``` + +### Resend + +```typescript +import { resendAdapter } from '@payloadcms/email-resend' + +export default buildConfig({ + email: resendAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + apiKey: process.env.RESEND_API_KEY, + }), +}) +``` + +## Important Notes + +1. **MongoDB Transactions**: Require replica set configuration +2. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +3. **Pass req**: Always pass `req` to nested operations in hooks for transaction safety +4. **Point Fields**: Not supported in SQLite diff --git a/templates/with-vercel-mongodb/.cursor/rules/collections.md b/templates/with-vercel-mongodb/.cursor/rules/collections.md new file mode 100644 index 00000000000..af625108e60 --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/collections.md @@ -0,0 +1,171 @@ +--- +title: Collections +description: Collection configurations and patterns +tags: [payload, collections, auth, upload, drafts] +--- + +# Payload CMS Collections + +## Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +## Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Upload Collection + +```typescript +export const Media: CollectionConfig = { + slug: 'media', + upload: { + staticDir: 'media', + mimeTypes: ['image/*'], + imageSizes: [ + { + name: 'thumbnail', + width: 400, + height: 300, + position: 'centre', + }, + { + name: 'card', + width: 768, + height: 1024, + }, + ], + adminThumbnail: 'thumbnail', + focalPoint: true, + crop: true, + }, + access: { + read: () => true, + }, + fields: [ + { + name: 'alt', + type: 'text', + required: true, + }, + ], +} +``` + +## Versioning & Drafts + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} +``` + +### Draft API Usage + +```typescript +// Create draft +await payload.create({ + collection: 'posts', + data: { title: 'Draft Post' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft version if exists +}) +``` + +## Globals + +Globals are single-instance documents (not collections). + +```typescript +import type { GlobalConfig } from 'payload' + +export const Header: GlobalConfig = { + slug: 'header', + label: 'Header', + admin: { + group: 'Settings', + }, + fields: [ + { + name: 'logo', + type: 'upload', + relationTo: 'media', + required: true, + }, + { + name: 'nav', + type: 'array', + maxRows: 8, + fields: [ + { + name: 'link', + type: 'relationship', + relationTo: 'pages', + }, + { + name: 'label', + type: 'text', + }, + ], + }, + ], +} +``` diff --git a/templates/with-vercel-mongodb/.cursor/rules/components.md b/templates/with-vercel-mongodb/.cursor/rules/components.md new file mode 100644 index 00000000000..8610b8d7b33 --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/components.md @@ -0,0 +1,794 @@ +# Custom Components in Payload CMS + +Custom Components allow you to fully customize the Admin Panel by swapping in your own React components. You can replace nearly every part of the interface or add entirely new functionality. + +## Component Types + +There are four main types of Custom Components: + +1. **Root Components** - Affect the Admin Panel globally (logo, nav, header) +2. **Collection Components** - Specific to collection views +3. **Global Components** - Specific to global document views +4. **Field Components** - Custom field UI and cells + +## Defining Custom Components + +### Component Paths + +Components are defined using file paths (not direct imports) to keep the config lightweight and Node.js compatible. + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + logout: { + Button: '/src/components/Logout#MyComponent', // Named export + }, + Nav: '/src/components/Nav', // Default export + }, + }, +}) +``` + +**Component Path Rules:** + +1. Paths are relative to project root (or `config.admin.importMap.baseDir`) +2. For **named exports**: append `#ExportName` or use `exportName` property +3. For **default exports**: no suffix needed +4. File extensions can be omitted + +### Component Config Object + +Instead of a string path, you can pass a config object: + +```typescript +{ + logout: { + Button: { + path: '/src/components/Logout', + exportName: 'MyComponent', + clientProps: { customProp: 'value' }, + serverProps: { asyncData: someData }, + }, + }, +} +``` + +**Config Properties:** + +| Property | Description | +| ------------- | ----------------------------------------------------- | +| `path` | File path to component (named exports via `#`) | +| `exportName` | Named export (alternative to `#` in path) | +| `clientProps` | Props for Client Components (must be serializable) | +| `serverProps` | Props for Server Components (can be non-serializable) | + +### Setting Base Directory + +```typescript +import path from 'path' +import { fileURLToPath } from 'node:url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), // Set base directory + }, + components: { + Nav: '/components/Nav', // Now relative to src/ + }, + }, +}) +``` + +## Server vs Client Components + +**All components are React Server Components by default.** + +### Server Components (Default) + +Can use Local API directly, perform async operations, and access full Payload instance. + +```tsx +import React from 'react' +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const page = await payload.findByID({ + collection: 'pages', + id: '123', + }) + + return

{page.title}

+} + +export default MyServerComponent +``` + +### Client Components + +Use the `'use client'` directive for interactivity, hooks, state, etc. + +```tsx +'use client' +import React, { useState } from 'react' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + + return +} +``` + +**Important:** Client Components cannot receive non-serializable props (functions, class instances, etc.). Payload automatically strips these when passing to client components. + +## Default Props + +All Custom Components receive these props by default: + +| Prop | Description | Type | +| --------- | ---------------------------------------- | --------- | +| `payload` | Payload instance (Local API access) | `Payload` | +| `i18n` | Internationalization object | `I18n` | +| `locale` | Current locale (if localization enabled) | `string` | + +**Server Component Example:** + +```tsx +async function MyComponent({ payload, i18n, locale }) { + const data = await payload.find({ + collection: 'posts', + locale, + }) + + return
{data.docs.length} posts
+} +``` + +**Client Component Example:** + +```tsx +'use client' +import { usePayload, useLocale, useTranslation } from '@payloadcms/ui' + +export function MyComponent() { + // Access via hooks in client components + const { getLocal, getByID } = usePayload() + const locale = useLocale() + const { t, i18n } = useTranslation() + + return
{t('myKey')}
+} +``` + +## Custom Props + +Pass additional props using `clientProps` or `serverProps`: + +```typescript +{ + logout: { + Button: { + path: '/components/Logout', + clientProps: { + buttonText: 'Sign Out', + onLogout: () => console.log('Logged out'), + }, + }, + }, +} +``` + +Receive in component: + +```tsx +'use client' +export function Logout({ buttonText, onLogout }) { + return +} +``` + +## Root Components + +Root Components affect the entire Admin Panel. + +### Available Root Components + +| Component | Description | Config Path | +| ----------------- | -------------------------------- | ---------------------------------- | +| `Nav` | Entire navigation sidebar | `admin.components.Nav` | +| `graphics.Icon` | Small icon (used in nav) | `admin.components.graphics.Icon` | +| `graphics.Logo` | Full logo (used on login) | `admin.components.graphics.Logo` | +| `logout.Button` | Logout button | `admin.components.logout.Button` | +| `actions` | Header actions (array) | `admin.components.actions` | +| `header` | Above header (array) | `admin.components.header` | +| `beforeDashboard` | Before dashboard content (array) | `admin.components.beforeDashboard` | +| `afterDashboard` | After dashboard content (array) | `admin.components.afterDashboard` | +| `beforeLogin` | Before login form (array) | `admin.components.beforeLogin` | +| `afterLogin` | After login form (array) | `admin.components.afterLogin` | +| `beforeNavLinks` | Before nav links (array) | `admin.components.beforeNavLinks` | +| `afterNavLinks` | After nav links (array) | `admin.components.afterNavLinks` | +| `settingsMenu` | Settings menu items (array) | `admin.components.settingsMenu` | +| `providers` | Custom React Context providers | `admin.components.providers` | +| `views` | Custom views (dashboard, etc.) | `admin.components.views` | + +### Example: Custom Logo + +```typescript +export default buildConfig({ + admin: { + components: { + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + }, + }, +}) +``` + +```tsx +// components/Logo.tsx +export default function Logo() { + return My Brand +} +``` + +### Example: Header Actions + +```typescript +export default buildConfig({ + admin: { + components: { + actions: ['/components/ClearCacheButton', '/components/PreviewButton'], + }, + }, +}) +``` + +```tsx +// components/ClearCacheButton.tsx +'use client' +export default function ClearCacheButton() { + return ( + + ) +} +``` + +## Collection Components + +Collection Components are specific to a collection's views. + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view components + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/CustomSaveDraft', + PublishButton: '/components/CustomPublish', + }, + + // List view components + list: { + Header: '/components/PostsListHeader', + beforeList: ['/components/ListFilters'], + afterList: ['/components/ListFooter'], + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Global Components + +Similar to Collection Components but for Global documents. + +```typescript +import type { GlobalConfig } from 'payload' + +export const Settings: GlobalConfig = { + slug: 'settings', + admin: { + components: { + edit: { + PreviewButton: '/components/SettingsPreview', + SaveButton: '/components/SettingsSave', + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Field Components + +Customize how fields render in Edit and List views. + +### Field Component (Edit View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Field: '/components/StatusField', + }, + }, +} +``` + +```tsx +// components/StatusField.tsx +'use client' +import { useField } from '@payloadcms/ui' +import type { SelectFieldClientComponent } from 'payload' + +export const StatusField: SelectFieldClientComponent = ({ path, field }) => { + const { value, setValue } = useField({ path }) + + return ( +
+ + +
+ ) +} +``` + +### Cell Component (List View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Cell: '/components/StatusCell', + }, + }, +} +``` + +```tsx +// components/StatusCell.tsx +import type { SelectFieldCellComponent } from 'payload' + +export const StatusCell: SelectFieldCellComponent = ({ data, cellData }) => { + const isPublished = cellData === 'published' + + return ( + + {cellData} + + ) +} +``` + +### UI Field (Presentational Only) + +Special field type for adding custom UI without affecting data: + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +```tsx +// components/RefundButton.tsx +'use client' +import { useDocumentInfo } from '@payloadcms/ui' + +export default function RefundButton() { + const { id } = useDocumentInfo() + + return ( + + ) +} +``` + +## Using Hooks + +Payload provides many React hooks for Client Components: + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Current document info (id, slug, etc.) + useField, // Field value and setValue + useForm, // Form state and dispatch + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +**Important:** These hooks only work in Client Components within the Admin Panel context. + +## Accessing Payload Config + +**In Server Components:** + +```tsx +async function MyServerComponent({ payload }) { + const { config } = payload + return
{config.serverURL}
+} +``` + +**In Client Components:** + +```tsx +'use client' +import { useConfig } from '@payloadcms/ui' + +export function MyClientComponent() { + const { config } = useConfig() // Client-safe config + return
{config.serverURL}
+} +``` + +**Important:** Client Components receive a serializable version of the config (functions, validation, etc. are stripped). + +## Field Config Access + +**Server Component:** + +```tsx +import type { TextFieldServerComponent } from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = ({ field }) => { + return
Field name: {field.name}
+} +``` + +**Client Component:** + +```tsx +'use client' +import type { TextFieldClientComponent } from 'payload' + +export const MyFieldComponent: TextFieldClientComponent = ({ clientField }) => { + // clientField has non-serializable props removed + return
Field name: {clientField.name}
+} +``` + +## Translations (i18n) + +**Server Component:** + +```tsx +import { getTranslation } from '@payloadcms/translations' + +async function MyServerComponent({ i18n }) { + const translatedTitle = getTranslation(myTranslation, i18n) + return

{translatedTitle}

+} +``` + +**Client Component:** + +```tsx +'use client' +import { useTranslation } from '@payloadcms/ui' + +export function MyClientComponent() { + const { t, i18n } = useTranslation() + + return ( +
+

{t('namespace:key', { variable: 'value' })}

+

Language: {i18n.language}

+
+ ) +} +``` + +## Styling Components + +### Using CSS Variables + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Custom Component
+} +``` + +```scss +// styles.scss +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} +``` + +### Importing Payload SCSS + +```scss +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +## Common Patterns + +### Conditional Field Visibility + +```tsx +'use client' +import { useFormFields } from '@payloadcms/ui' +import type { TextFieldClientComponent } from 'payload' + +export const ConditionalField: TextFieldClientComponent = ({ path }) => { + const showField = useFormFields(([fields]) => fields.enableFeature?.value) + + if (!showField) return null + + return +} +``` + +### Loading Data from API + +```tsx +'use client' +import { useState, useEffect } from 'react' + +export function DataLoader() { + const [data, setData] = useState(null) + + useEffect(() => { + fetch('/api/custom-data') + .then((res) => res.json()) + .then(setData) + }, []) + + return
{JSON.stringify(data)}
+} +``` + +### Using Local API in Server Components + +```tsx +import type { Payload } from 'payload' + +async function RelatedPosts({ payload, id }: { payload: Payload; id: string }) { + const post = await payload.findByID({ + collection: 'posts', + id, + depth: 0, + }) + + const related = await payload.find({ + collection: 'posts', + where: { + category: { equals: post.category }, + id: { not_equals: id }, + }, + limit: 5, + }) + + return ( +
+

Related Posts

+
    + {related.docs.map((doc) => ( +
  • {doc.title}
  • + ))} +
+
+ ) +} + +export default RelatedPosts +``` + +## Performance Best Practices + +### 1. Minimize Client Bundle Size + +```tsx +// ❌ BAD: Imports entire package +'use client' +import { Button } from '@payloadcms/ui' + +// ✅ GOOD: Tree-shakeable import for frontend +import { Button } from '@payloadcms/ui/elements/Button' +``` + +**Rule:** In Admin Panel UI, import from `@payloadcms/ui`. In frontend code, use specific paths. + +### 2. Optimize Re-renders + +```tsx +// ❌ BAD: Re-renders on every form change +'use client' +import { useForm } from '@payloadcms/ui' + +export function MyComponent() { + const { fields } = useForm() + // Re-renders on ANY field change +} + +// ✅ GOOD: Only re-renders when specific field changes +;('use client') +import { useFormFields } from '@payloadcms/ui' + +export function MyComponent({ path }) { + const value = useFormFields(([fields]) => fields[path]) + // Only re-renders when this field changes +} +``` + +### 3. Use Server Components When Possible + +```tsx +// ✅ GOOD: No JavaScript sent to client +async function PostCount({ payload }) { + const { totalDocs } = await payload.find({ + collection: 'posts', + limit: 0, + }) + + return

{totalDocs} posts

+} + +// Only use client components when you need: +// - State (useState, useReducer) +// - Effects (useEffect) +// - Event handlers (onClick, onChange) +// - Browser APIs (localStorage, window) +``` + +### 4. React Best Practices + +- Use React.memo() for expensive components +- Implement proper key props in lists +- Avoid inline function definitions in renders +- Use Suspense boundaries for async operations + +## Import Map + +Payload generates an import map at `app/(payload)/admin/importMap.js` that resolves all component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Override location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Type Safety + +Use Payload's TypeScript types for components: + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, +} from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = (props) => { + // Fully typed props +} +``` + +## Troubleshooting + +### "useConfig is undefined" or similar hook errors + +**Cause:** Dependency version mismatch between Payload packages. + +**Solution:** Pin all `@payloadcms/*` packages to the exact same version: + +```json +{ + "dependencies": { + "payload": "3.0.0", + "@payloadcms/ui": "3.0.0", + "@payloadcms/richtext-lexical": "3.0.0" + } +} +``` + +### Component not loading + +1. Check file path is correct (relative to baseDir) +2. Verify named export syntax: `/path/to/file#ExportName` +3. Run `payload generate:importmap` to regenerate +4. Check for TypeScript errors in component file + +## Resources + +- [Custom Components Docs](https://payloadcms.com/docs/custom-components/overview) +- [Root Components](https://payloadcms.com/docs/custom-components/root-components) +- [Custom Views](https://payloadcms.com/docs/custom-components/custom-views) +- [React Hooks](https://payloadcms.com/docs/admin/react-hooks) +- [Custom CSS](https://payloadcms.com/docs/admin/customizing-css) diff --git a/templates/with-vercel-mongodb/.cursor/rules/endpoints.md b/templates/with-vercel-mongodb/.cursor/rules/endpoints.md new file mode 100644 index 00000000000..8a2481dbe5d --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/endpoints.md @@ -0,0 +1,236 @@ +--- +title: Custom Endpoints +description: Custom REST API endpoints with authentication and helpers +tags: [payload, endpoints, api, routes, webhooks] +--- + +# Payload Custom Endpoints + +## Basic Endpoint Pattern + +Custom endpoints are **not authenticated by default**. Always check `req.user`. + +```typescript +import { APIError } from 'payload' +import type { Endpoint } from 'payload' + +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} +``` + +## Route Parameters + +```typescript +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Request Body Handling + +```typescript +// Manual JSON parsing +export const createEndpoint: Endpoint = { + path: '/create', + method: 'post', + handler: async (req) => { + const data = await req.json() + + const result = await req.payload.create({ + collection: 'posts', + data, + }) + + return Response.json(result) + }, +} + +// Using helper (handles JSON + files) +import { addDataAndFileToRequest } from 'payload' + +export const uploadEndpoint: Endpoint = { + path: '/upload', + method: 'post', + handler: async (req) => { + await addDataAndFileToRequest(req) + + // req.data contains parsed body + // req.file contains uploaded file (if multipart) + + const result = await req.payload.create({ + collection: 'media', + data: req.data, + file: req.file, + }) + + return Response.json(result) + }, +} +``` + +## Query Parameters + +```typescript +export const searchEndpoint: Endpoint = { + path: '/search', + method: 'get', + handler: async (req) => { + const url = new URL(req.url) + const query = url.searchParams.get('q') + const limit = parseInt(url.searchParams.get('limit') || '10') + + const results = await req.payload.find({ + collection: 'posts', + where: { + title: { + contains: query, + }, + }, + limit, + }) + + return Response.json(results) + }, +} +``` + +## CORS Headers + +```typescript +import { headersWithCors } from 'payload' + +export const corsEndpoint: Endpoint = { + path: '/public-data', + method: 'get', + handler: async (req) => { + const data = await fetchPublicData() + + return Response.json(data, { + headers: headersWithCors({ + headers: new Headers(), + req, + }), + }) + }, +} +``` + +## Error Handling + +```typescript +import { APIError } from 'payload' + +export const validateEndpoint: Endpoint = { + path: '/validate', + method: 'post', + handler: async (req) => { + const data = await req.json() + + if (!data.email) { + throw new APIError('Email is required', 400) + } + + return Response.json({ valid: true }) + }, +} +``` + +## Endpoint Placement + +### Collection Endpoints + +Mounted at `/api/{collection-slug}/{path}`. + +```typescript +export const Orders: CollectionConfig = { + slug: 'orders', + endpoints: [ + { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + // Available at: /api/orders/:id/tracking + const orderId = req.routeParams.id + return Response.json({ orderId }) + }, + }, + ], +} +``` + +### Global Endpoints + +Mounted at `/api/globals/{global-slug}/{path}`. + +```typescript +export const Settings: GlobalConfig = { + slug: 'settings', + endpoints: [ + { + path: '/clear-cache', + method: 'post', + handler: async (req) => { + // Available at: /api/globals/settings/clear-cache + await clearCache() + return Response.json({ message: 'Cache cleared' }) + }, + }, + ], +} +``` + +### Root Endpoints + +Mounted at `/api/{path}`. + +```typescript +export default buildConfig({ + endpoints: [ + { + path: '/hello', + method: 'get', + handler: () => { + // Available at: /api/hello + return Response.json({ message: 'Hello!' }) + }, + }, + ], +}) +``` + +## Best Practices + +1. **Always check authentication** - Custom endpoints are not authenticated by default +2. **Use `req.payload` for operations** - Ensures access control and hooks execute +3. **Use helpers for common tasks** - `addDataAndFileToRequest`, `headersWithCors` +4. **Throw `APIError` for errors** - Provides consistent error responses +5. **Return Web API `Response`** - Use `Response.json()` for consistent responses +6. **Validate input** - Check required fields, validate types +7. **Log errors** - Use `req.payload.logger` for debugging diff --git a/templates/with-vercel-mongodb/.cursor/rules/field-type-guards.md b/templates/with-vercel-mongodb/.cursor/rules/field-type-guards.md new file mode 100644 index 00000000000..3514ad44993 --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/field-type-guards.md @@ -0,0 +1,230 @@ +--- +title: Field Type Guards +description: Runtime field type checking and safe type narrowing +tags: [payload, typescript, type-guards, fields] +--- + +# Payload Field Type Guards + +Type guards for runtime field type checking and safe type narrowing. + +## Most Common Guards + +### fieldAffectsData + +**Most commonly used guard.** Checks if field stores data (has name and is not UI-only). + +```typescript +import { fieldAffectsData } from 'payload' + +function generateSchema(fields: Field[]) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + // Safe to access field.name + schema[field.name] = getFieldType(field) + } + }) +} + +// Filter data fields +const dataFields = fields.filter(fieldAffectsData) +``` + +### fieldHasSubFields + +Checks if field contains nested fields (group, array, row, or collapsible). + +```typescript +import { fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[]): void { + fields.forEach((field) => { + if (fieldHasSubFields(field)) { + // Safe to access field.fields + traverseFields(field.fields) + } + }) +} +``` + +### fieldIsArrayType + +Checks if field type is `'array'`. + +```typescript +import { fieldIsArrayType } from 'payload' + +if (fieldIsArrayType(field)) { + // field.type === 'array' + console.log(`Min rows: ${field.minRows}`) + console.log(`Max rows: ${field.maxRows}`) +} +``` + +## Capability Guards + +### fieldSupportsMany + +Checks if field can have multiple values (select, relationship, or upload with `hasMany`). + +```typescript +import { fieldSupportsMany } from 'payload' + +if (fieldSupportsMany(field)) { + // field.type is 'select' | 'relationship' | 'upload' + if (field.hasMany) { + console.log('Field accepts multiple values') + } +} +``` + +### fieldHasMaxDepth + +Checks if field is relationship/upload/join with numeric `maxDepth` property. + +```typescript +import { fieldHasMaxDepth } from 'payload' + +if (fieldHasMaxDepth(field)) { + // field.type is 'upload' | 'relationship' | 'join' + // AND field.maxDepth is number + const remainingDepth = field.maxDepth - currentDepth +} +``` + +### fieldIsVirtual + +Checks if field is virtual (computed or virtual relationship). + +```typescript +import { fieldIsVirtual } from 'payload' + +if (fieldIsVirtual(field)) { + // field.virtual is truthy + if (typeof field.virtual === 'string') { + console.log(`Virtual path: ${field.virtual}`) + } +} +``` + +## Type Checking Guards + +### fieldIsBlockType + +```typescript +import { fieldIsBlockType } from 'payload' + +if (fieldIsBlockType(field)) { + // field.type === 'blocks' + field.blocks.forEach((block) => { + console.log(`Block: ${block.slug}`) + }) +} +``` + +### fieldIsGroupType + +```typescript +import { fieldIsGroupType } from 'payload' + +if (fieldIsGroupType(field)) { + // field.type === 'group' + console.log(`Interface: ${field.interfaceName}`) +} +``` + +### fieldIsPresentationalOnly + +```typescript +import { fieldIsPresentationalOnly } from 'payload' + +if (fieldIsPresentationalOnly(field)) { + // field.type === 'ui' + // Skip in data operations, GraphQL schema, etc. + return +} +``` + +## Common Patterns + +### Recursive Field Traversal + +```typescript +import { fieldAffectsData, fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[], callback: (field: Field) => void) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + callback(field) + } + + if (fieldHasSubFields(field)) { + traverseFields(field.fields, callback) + } + }) +} +``` + +### Filter Data-Bearing Fields + +```typescript +import { fieldAffectsData, fieldIsPresentationalOnly, fieldIsHiddenOrDisabled } from 'payload' + +const dataFields = fields.filter( + (field) => + fieldAffectsData(field) && !fieldIsPresentationalOnly(field) && !fieldIsHiddenOrDisabled(field), +) +``` + +### Container Type Switching + +```typescript +import { fieldIsArrayType, fieldIsBlockType, fieldHasSubFields } from 'payload' + +if (fieldIsArrayType(field)) { + // Handle array-specific logic +} else if (fieldIsBlockType(field)) { + // Handle blocks-specific logic +} else if (fieldHasSubFields(field)) { + // Handle group/row/collapsible +} +``` + +### Safe Property Access + +```typescript +import { fieldSupportsMany, fieldHasMaxDepth } from 'payload' + +// With guard - safe access +if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') +} + +if (fieldHasMaxDepth(field)) { + const depth = field.maxDepth // TypeScript knows this is number +} +``` + +## All Available Guards + +| Type Guard | Checks For | Use When | +| --------------------------- | --------------------------------- | ---------------------------------------- | +| `fieldAffectsData` | Field stores data (has name) | Need to access field data or name | +| `fieldHasSubFields` | Field contains nested fields | Recursively traverse fields | +| `fieldIsArrayType` | Field is array type | Distinguish arrays from other containers | +| `fieldIsBlockType` | Field is blocks type | Handle blocks-specific logic | +| `fieldIsGroupType` | Field is group type | Handle group-specific logic | +| `fieldSupportsMany` | Field can have multiple values | Check for `hasMany` support | +| `fieldHasMaxDepth` | Field supports depth control | Control relationship/upload/join depth | +| `fieldIsPresentationalOnly` | Field is UI-only | Exclude from data operations | +| `fieldIsSidebar` | Field positioned in sidebar | Separate sidebar rendering | +| `fieldIsID` | Field name is 'id' | Special ID field handling | +| `fieldIsHiddenOrDisabled` | Field is hidden or disabled | Filter from UI operations | +| `fieldShouldBeLocalized` | Field needs localization | Proper locale table checks | +| `fieldIsVirtual` | Field is virtual | Skip in database transforms | +| `tabHasName` | Tab is named (stores data) | Distinguish named vs unnamed tabs | +| `groupHasName` | Group is named (stores data) | Distinguish named vs unnamed groups | +| `optionIsObject` | Option is `{label, value}` | Access option properties safely | +| `optionsAreObjects` | All options are objects | Batch option processing | +| `optionIsValue` | Option is string value | Handle string options | +| `valueIsValueWithRelation` | Value is polymorphic relationship | Handle polymorphic relationships | diff --git a/templates/with-vercel-mongodb/.cursor/rules/fields.md b/templates/with-vercel-mongodb/.cursor/rules/fields.md new file mode 100644 index 00000000000..8468e41f599 --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/fields.md @@ -0,0 +1,317 @@ +--- +title: Fields +description: Field types, patterns, and configurations +tags: [payload, fields, validation, conditional] +--- + +# Payload CMS Fields + +## Common Field Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## Field Types + +### Text Field + +```typescript +{ + name: 'title', + type: 'text', + required: true, + unique: true, + minLength: 5, + maxLength: 100, + index: true, + localized: true, + defaultValue: 'Default Title', + validate: (value) => Boolean(value) || 'Required', + admin: { + placeholder: 'Enter title...', + position: 'sidebar', + condition: (data) => data.showTitle === true, + }, +} +``` + +### Rich Text (Lexical) + +```typescript +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { HeadingFeature, LinkFeature } from '@payloadcms/richtext-lexical' + +{ + name: 'content', + type: 'richText', + required: true, + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + HeadingFeature({ + enabledHeadingSizes: ['h1', 'h2', 'h3'], + }), + LinkFeature({ + enabledCollections: ['posts', 'pages'], + }), + ], + }), +} +``` + +### Relationship + +```typescript +// Single relationship +{ + name: 'author', + type: 'relationship', + relationTo: 'users', + required: true, + maxDepth: 2, +} + +// Multiple relationships (hasMany) +{ + name: 'categories', + type: 'relationship', + relationTo: 'categories', + hasMany: true, + filterOptions: { + active: { equals: true }, + }, +} + +// Polymorphic relationship +{ + name: 'relatedContent', + type: 'relationship', + relationTo: ['posts', 'pages'], + hasMany: true, +} +``` + +### Array + +```typescript +{ + name: 'slides', + type: 'array', + minRows: 2, + maxRows: 10, + labels: { + singular: 'Slide', + plural: 'Slides', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'image', + type: 'upload', + relationTo: 'media', + }, + ], + admin: { + initCollapsed: true, + }, +} +``` + +### Blocks + +```typescript +import type { Block } from 'payload' + +const HeroBlock: Block = { + slug: 'hero', + interfaceName: 'HeroBlock', + fields: [ + { + name: 'heading', + type: 'text', + required: true, + }, + { + name: 'background', + type: 'upload', + relationTo: 'media', + }, + ], +} + +const ContentBlock: Block = { + slug: 'content', + fields: [ + { + name: 'text', + type: 'richText', + }, + ], +} + +{ + name: 'layout', + type: 'blocks', + blocks: [HeroBlock, ContentBlock], +} +``` + +### Select + +```typescript +{ + name: 'status', + type: 'select', + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + ], + defaultValue: 'draft', + required: true, +} + +// Multiple select +{ + name: 'tags', + type: 'select', + hasMany: true, + options: ['tech', 'news', 'sports'], +} +``` + +### Upload + +```typescript +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + required: true, + filterOptions: { + mimeType: { contains: 'image' }, + }, +} +``` + +### Point (Geolocation) + +```typescript +{ + name: 'location', + type: 'point', + label: 'Location', + required: true, +} + +// Query by distance +const nearbyLocations = await payload.find({ + collection: 'stores', + where: { + location: { + near: [10, 20], // [longitude, latitude] + maxDistance: 5000, // in meters + minDistance: 1000, + }, + }, +}) +``` + +### Join Fields (Reverse Relationships) + +```typescript +// From Users collection - show user's orders +{ + name: 'orders', + type: 'join', + collection: 'orders', + on: 'customer', // The field in 'orders' that references this user +} +``` + +### Tabs & Groups + +```typescript +// Tabs +{ + type: 'tabs', + tabs: [ + { + label: 'Content', + fields: [ + { name: 'title', type: 'text' }, + { name: 'body', type: 'richText' }, + ], + }, + { + label: 'SEO', + fields: [ + { name: 'metaTitle', type: 'text' }, + { name: 'metaDescription', type: 'textarea' }, + ], + }, + ], +} + +// Group (named) +{ + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], +} +``` + +## Validation + +```typescript +{ + name: 'email', + type: 'email', + validate: (value, { operation, data, siblingData }) => { + if (operation === 'create' && !value) { + return 'Email is required' + } + if (value && !value.includes('@')) { + return 'Invalid email format' + } + return true + }, +} +``` diff --git a/templates/with-vercel-mongodb/.cursor/rules/hooks.md b/templates/with-vercel-mongodb/.cursor/rules/hooks.md new file mode 100644 index 00000000000..1f168f9eaeb --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/hooks.md @@ -0,0 +1,175 @@ +--- +title: Hooks +description: Collection hooks, field hooks, and context patterns +tags: [payload, hooks, lifecycle, context] +--- + +# Payload CMS Hooks + +## Collection Hooks + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Field Hooks + +```typescript +import type { FieldHook } from 'payload' + +const beforeValidateHook: FieldHook = ({ value }) => { + return value.trim().toLowerCase() +} + +const afterReadHook: FieldHook = ({ value, req }) => { + // Hide email from non-admins + if (!req.user?.roles?.includes('admin')) { + return value.replace(/(.{2})(.*)(@.*)/, '$1***$3') + } + return value +} + +{ + name: 'email', + type: 'email', + hooks: { + beforeValidate: [beforeValidateHook], + afterRead: [afterReadHook], + }, +} +``` + +## Hook Context + +Share data between hooks or control hook behavior using request context: + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + beforeChange: [ + async ({ context }) => { + context.expensiveData = await fetchExpensiveData() + }, + ], + afterChange: [ + async ({ context, doc }) => { + // Reuse from previous hook + await processData(doc, context.expensiveData) + }, + ], + }, +} +``` + +## Next.js Revalidation Pattern + +```typescript +import type { CollectionAfterChangeHook } from 'payload' +import { revalidatePath } from 'next/cache' + +export const revalidatePage: CollectionAfterChangeHook = ({ + doc, + previousDoc, + req: { payload, context }, +}) => { + if (!context.disableRevalidate) { + if (doc._status === 'published') { + const path = doc.slug === 'home' ? '/' : `/${doc.slug}` + payload.logger.info(`Revalidating page at path: ${path}`) + revalidatePath(path) + } + + // Revalidate old path if unpublished + if (previousDoc?._status === 'published' && doc._status !== 'published') { + const oldPath = previousDoc.slug === 'home' ? '/' : `/${previousDoc.slug}` + revalidatePath(oldPath) + } + } + return doc +} +``` + +## Date Field Auto-Set + +```typescript +{ + name: 'publishedOn', + type: 'date', + hooks: { + beforeChange: [ + ({ siblingData, value }) => { + if (siblingData._status === 'published' && !value) { + return new Date() + } + return value + }, + ], + }, +} +``` + +## Best Practices + +- Use `beforeValidate` for data formatting +- Use `beforeChange` for business logic +- Use `afterChange` for side effects +- Use `afterRead` for computed fields +- Store expensive operations in `context` +- Pass `req` to nested operations for transaction safety +- Use context flags to prevent infinite loops diff --git a/templates/with-vercel-mongodb/.cursor/rules/payload-overview.md b/templates/with-vercel-mongodb/.cursor/rules/payload-overview.md new file mode 100644 index 00000000000..290c47822ab --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/payload-overview.md @@ -0,0 +1,126 @@ +--- +title: Payload CMS Overview +description: Core principles and quick reference for Payload CMS development +tags: [payload, overview, quickstart] +--- + +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Quick Reference + +| Task | Solution | +| --------------------- | ---------------------------------- | +| Auto-generate slugs | `slugField()` | +| Restrict by user | Access control with query | +| Local API user ops | `user` + `overrideAccess: false` | +| Draft/publish | `versions: { drafts: true }` | +| Computed fields | `virtual: true` with afterRead | +| Conditional fields | `admin.condition` | +| Custom validation | `validate` function | +| Filter relationships | `filterOptions` on field | +| Select fields | `select` parameter | +| Auto-set dates | beforeChange hook | +| Prevent loops | `req.context` check | +| Cascading deletes | beforeDelete hook | +| Geospatial queries | `point` field with `near`/`within` | +| Reverse relationships | `join` field type | +| Query relationships | Nested property syntax | +| Complex queries | AND/OR logic | +| Transactions | Pass `req` to operations | +| Background jobs | Jobs queue with tasks | +| Custom routes | Collection custom endpoints | +| Cloud storage | Storage adapter plugins | +| Multi-language | `localization` + `localized: true` | + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/with-vercel-mongodb/.cursor/rules/plugin-development.md b/templates/with-vercel-mongodb/.cursor/rules/plugin-development.md new file mode 100644 index 00000000000..d92bb12fb40 --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/plugin-development.md @@ -0,0 +1,323 @@ +--- +title: Plugin Development +description: Creating Payload CMS plugins with TypeScript patterns +tags: [payload, plugins, architecture, patterns] +--- + +# Payload Plugin Development + +## Plugin Architecture + +Plugins are functions that receive configuration options and return a function that transforms the Payload config: + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + enabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + // Transform config here + }) +``` + +**Key Pattern:** Double arrow function (currying) + +- First function: Accepts plugin options, returns plugin function +- Second function: Accepts Payload config, returns modified config + +## Adding Fields to Collections + +```typescript +export const seoPlugin = + (options: { collections?: string[] }): Plugin => + (config: Config): Config => { + const seoFields: Field[] = [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], + }, + ] + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...seoFields], + } + } + return collection + }), + } + } +``` + +## Adding New Collections + +```typescript +export const redirectsPlugin = + (options: { overrides?: Partial }): Plugin => + (config: Config): Config => { + const redirectsCollection: CollectionConfig = { + slug: 'redirects', + access: { read: () => true }, + fields: [ + { name: 'from', type: 'text', required: true, unique: true }, + { name: 'to', type: 'text', required: true }, + ], + ...options.overrides, + } + + return { + ...config, + collections: [...(config.collections || []), redirectsCollection], + } + } +``` + +## Adding Hooks + +```typescript +const resaveChildrenHook: CollectionAfterChangeHook = async ({ doc, req, operation }) => { + if (operation === 'update') { + const children = await req.payload.find({ + collection: 'pages', + where: { parent: { equals: doc.id } }, + }) + + for (const child of children.docs) { + await req.payload.update({ + collection: 'pages', + id: child.id, + data: child, + }) + } + } + return doc +} + +export const nestedDocsPlugin = + (options: { collections: string[] }): Plugin => + (config: Config): Config => ({ + ...config, + collections: (config.collections || []).map((collection) => { + if (options.collections.includes(collection.slug)) { + return { + ...collection, + hooks: { + ...(collection.hooks || {}), + afterChange: [resaveChildrenHook, ...(collection.hooks?.afterChange || [])], + }, + } + } + return collection + }), + }) +``` + +## Adding Root-Level Endpoints + +```typescript +export const seoPlugin = + (options: { generateTitle?: (doc: any) => string }): Plugin => + (config: Config): Config => { + const generateTitleEndpoint: Endpoint = { + path: '/plugin-seo/generate-title', + method: 'post', + handler: async (req) => { + const data = await req.json?.() + const result = options.generateTitle ? options.generateTitle(data.doc) : '' + return Response.json({ result }) + }, + } + + return { + ...config, + endpoints: [...(config.endpoints ?? []), generateTitleEndpoint], + } + } +``` + +## Field Overrides with Defaults + +```typescript +type FieldsOverride = (args: { defaultFields: Field[] }) => Field[] + +interface PluginConfig { + collections?: string[] + fields?: FieldsOverride +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const defaultFields: Field[] = [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ] + + const fields = + options.fields && typeof options.fields === 'function' + ? options.fields({ defaultFields }) + : defaultFields + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...fields], + } + } + return collection + }), + } + } +``` + +## Disable Plugin Pattern + +```typescript +interface PluginConfig { + disabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + // Always add collections/fields for database schema consistency + if (!config.collections) { + config.collections = [] + } + + config.collections.push({ + slug: 'plugin-collection', + fields: [{ name: 'title', type: 'text' }], + }) + + // If disabled, return early but keep schema changes + if (options.disabled) { + return config + } + + // Add endpoints, hooks, components only when enabled + config.endpoints = [ + ...(config.endpoints ?? []), + { + path: '/my-endpoint', + method: 'get', + handler: async () => Response.json({ message: 'Hello' }), + }, + ] + + return config + } +``` + +## Admin Components + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + if (!config.admin) config.admin = {} + if (!config.admin.components) config.admin.components = {} + if (!config.admin.components.beforeDashboard) { + config.admin.components.beforeDashboard = [] + } + + // Add client component + config.admin.components.beforeDashboard.push('my-plugin-name/client#BeforeDashboardClient') + + // Add server component (RSC) + config.admin.components.beforeDashboard.push('my-plugin-name/rsc#BeforeDashboardServer') + + return config + } +``` + +## onInit Hook + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const incomingOnInit = config.onInit + + config.onInit = async (payload) => { + // IMPORTANT: Call existing onInit first + if (incomingOnInit) await incomingOnInit(payload) + + // Plugin initialization + payload.logger.info('Plugin initialized') + + // Example: Seed data + const { totalDocs } = await payload.count({ + collection: 'plugin-collection', + where: { id: { equals: 'seeded-by-plugin' } }, + }) + + if (totalDocs === 0) { + await payload.create({ + collection: 'plugin-collection', + data: { id: 'seeded-by-plugin' }, + }) + } + } + + return config + } +``` + +## Best Practices + +### Preserve Existing Config + +```typescript +// ✅ Good +collections: [...(config.collections || []), newCollection] + +// ❌ Bad +collections: [newCollection] +``` + +### Respect User Overrides + +```typescript +const collection: CollectionConfig = { + slug: 'redirects', + fields: defaultFields, + ...options.overrides, // User overrides last +} +``` + +### Hook Composition + +```typescript +hooks: { + ...collection.hooks, + afterChange: [ + myHook, + ...(collection.hooks?.afterChange || []), + ], +} +``` + +### Type Safety + +```typescript +import type { Config, Plugin, CollectionConfig, Field } from 'payload' +``` diff --git a/templates/with-vercel-mongodb/.cursor/rules/queries.md b/templates/with-vercel-mongodb/.cursor/rules/queries.md new file mode 100644 index 00000000000..4920ec85f09 --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/queries.md @@ -0,0 +1,223 @@ +--- +title: Queries +description: Local API, REST, and GraphQL query patterns +tags: [payload, queries, local-api, rest, graphql] +--- + +# Payload CMS Queries + +## Query Operators + +```typescript +// Equals +{ color: { equals: 'blue' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater/less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In/not in +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (point fields) +{ location: { near: [10, 20, 5000] } } // [lng, lat, maxDistance] +``` + +## AND/OR Logic + +```typescript +{ + or: [ + { color: { equals: 'mint' } }, + { + and: [ + { color: { equals: 'white' } }, + { featured: { equals: false } }, + ], + }, + ], +} +``` + +## Nested Properties + +```typescript +{ + 'author.role': { equals: 'editor' }, + 'meta.featured': { exists: true }, +} +``` + +## Local API + +```typescript +// Find documents +const posts = await payload.find({ + collection: 'posts', + where: { + status: { equals: 'published' }, + 'author.name': { contains: 'john' }, + }, + depth: 2, // Populate relationships + limit: 10, + page: 1, + sort: '-createdAt', + locale: 'en', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const post = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { + status: 'published', + }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) + +// Count +const count = await payload.count({ + collection: 'posts', + where: { + status: { equals: 'published' }, + }, +}) +``` + +## Access Control in Local API + +**CRITICAL**: Local API bypasses access control by default (`overrideAccess: true`). + +```typescript +// ❌ WRONG: User is passed but access control is bypassed +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + // Result: Operation runs with ADMIN privileges +}) + +// ✅ CORRECT: Respects user's access control permissions +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + overrideAccess: false, // Required to enforce access control +}) + +// Administrative operation (intentionally bypass access control) +const allPosts = await payload.find({ + collection: 'posts', + // No user parameter, overrideAccess defaults to true +}) +``` + +**When to use `overrideAccess: false`:** + +- Performing operations on behalf of a user +- Testing access control logic +- API routes that should respect user permissions + +## REST API + +```typescript +import { stringify } from 'qs-esm' + +const query = { + status: { equals: 'published' }, +} + +const queryString = stringify( + { + where: query, + depth: 2, + limit: 10, + }, + { addQueryPrefix: true }, +) + +const response = await fetch(`https://api.example.com/api/posts${queryString}`) +const data = await response.json() +``` + +### REST Endpoints + +``` +GET /api/{collection} - Find documents +GET /api/{collection}/{id} - Find by ID +POST /api/{collection} - Create +PATCH /api/{collection}/{id} - Update +DELETE /api/{collection}/{id} - Delete +GET /api/{collection}/count - Count documents + +GET /api/globals/{slug} - Get global +POST /api/globals/{slug} - Update global +``` + +## GraphQL + +```graphql +query { + Posts(where: { status: { equals: published } }, limit: 10, sort: "-createdAt") { + docs { + id + title + author { + name + } + } + totalDocs + hasNextPage + } +} + +mutation { + createPost(data: { title: "New Post", status: draft }) { + id + title + } +} +``` + +## Performance Best Practices + +- Set `maxDepth` on relationships to prevent over-fetching +- Use `select` to limit returned fields +- Index frequently queried fields +- Use `virtual` fields for computed data +- Cache expensive operations in hook `context` diff --git a/templates/with-vercel-mongodb/.cursor/rules/security-critical.mdc b/templates/with-vercel-mongodb/.cursor/rules/security-critical.mdc new file mode 100644 index 00000000000..adf5d9e225d --- /dev/null +++ b/templates/with-vercel-mongodb/.cursor/rules/security-critical.mdc @@ -0,0 +1,122 @@ +--- +title: Critical Security Patterns +description: The three most important security patterns in Payload CMS +tags: [payload, security, critical, access-control, transactions, hooks] +priority: high +--- + +# CRITICAL SECURITY PATTERNS + +These are the three most critical security patterns that MUST be followed in every Payload CMS project. + +## 1. Local API Access Control (MOST IMPORTANT) + +**By default, Local API operations bypass ALL access control**, even when passing a user. + +```typescript +// ❌ SECURITY BUG: Passes user but ignores their permissions +await payload.find({ + collection: 'posts', + user: someUser, // Access control is BYPASSED! +}) + +// ✅ SECURE: Actually enforces the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED for access control +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**When to use each:** + +- `overrideAccess: true` (default) - Server-side operations you trust (cron jobs, system tasks) +- `overrideAccess: false` - When operating on behalf of a user (API routes, webhooks) + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +## 2. Transaction Safety in Hooks + +**Nested operations in hooks without `req` break transaction atomicity.** + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ] +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ] +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +## 3. Prevent Infinite Hook Loops + +**Hooks triggering operations that trigger the same hooks create infinite loops.** + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ] +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ] +} +``` + +**Rule**: Use `req.context` flags to prevent hook loops diff --git a/templates/with-vercel-mongodb/AGENTS.md b/templates/with-vercel-mongodb/AGENTS.md new file mode 100644 index 00000000000..633b29b1f61 --- /dev/null +++ b/templates/with-vercel-mongodb/AGENTS.md @@ -0,0 +1,1141 @@ +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default +6. **Access Control**: Ensure roles exist when modifiyng collection or globals with access controls + +### Code Validation + +- To validate typescript correctness after modifying code run `tsc --noEmit` +- Generate import maps after creating or modifying components. + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Configuration + +### Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Collections + +### Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +### Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Fields + +### Common Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## CRITICAL SECURITY PATTERNS + +### 1. Local API Access Control (MOST IMPORTANT) + +```typescript +// ❌ SECURITY BUG: Access control bypassed +await payload.find({ + collection: 'posts', + user: someUser, // Ignored! Operation runs with ADMIN privileges +}) + +// ✅ SECURE: Enforces user permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +### 2. Transaction Safety in Hooks + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ], +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ], +} +``` + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +### 3. Prevent Infinite Hook Loops + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ], +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ], +} +``` + +## Access Control + +### Collection-Level Access + +```typescript +import type { Access } from 'payload' + +// Boolean return +const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Query constraint (row-level security) +const ownPostsOnly: Access = ({ req: { user } }) => { + if (!user) return false + if (user?.roles?.includes('admin')) return true + + return { + author: { equals: user.id }, + } +} + +// Async access check +const projectMemberAccess: Access = async ({ req, id }) => { + const { user, payload } = req + + if (!user) return false + if (user.roles?.includes('admin')) return true + + const project = await payload.findByID({ + collection: 'projects', + id: id as string, + depth: 0, + }) + + return project.members?.includes(user.id) +} +``` + +### Field-Level Access + +```typescript +// Field access ONLY returns boolean (no query constraints) +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +### Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Hooks + +### Common Hook Patterns + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Queries + +### Local API + +```typescript +// Find with complex query +const posts = await payload.find({ + collection: 'posts', + where: { + and: [{ status: { equals: 'published' } }, { 'author.name': { contains: 'john' } }], + }, + depth: 2, // Populate relationships + limit: 10, + sort: '-createdAt', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const newPost = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { status: 'published' }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) +``` + +### Query Operators + +```typescript +// Equals +{ status: { equals: 'published' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater than / less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In array +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (geospatial) +{ location: { near: [-122.4194, 37.7749, 10000] } } +``` + +### AND/OR Logic + +```typescript +{ + or: [ + { status: { equals: 'published' } }, + { author: { equals: user.id } }, + ], +} + +{ + and: [ + { status: { equals: 'published' } }, + { featured: { equals: true } }, + ], +} +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Components + +The Admin Panel can be extensively customized using React Components. Custom Components can be Server Components (default) or Client Components. + +### Defining Components + +Components are defined using **file paths** (not direct imports) in your config: + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + // Logo and branding + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + + // Navigation + Nav: '/components/CustomNav', + beforeNavLinks: ['/components/CustomNavItem'], + afterNavLinks: ['/components/NavFooter'], + + // Header + header: ['/components/AnnouncementBanner'], + actions: ['/components/ClearCache', '/components/Preview'], + + // Dashboard + beforeDashboard: ['/components/WelcomeMessage'], + afterDashboard: ['/components/Analytics'], + + // Auth + beforeLogin: ['/components/SSOButtons'], + logout: { Button: '/components/LogoutButton' }, + + // Settings + settingsMenu: ['/components/SettingsMenu'], + + // Views + views: { + dashboard: { Component: '/components/CustomDashboard' }, + }, + }, + }, +}) +``` + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Server vs Client Components + +**All components are Server Components by default** (can use Local API directly): + +```tsx +// Server Component (default) +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const posts = await payload.find({ collection: 'posts' }) + return
{posts.totalDocs} posts
+} + +export default MyServerComponent +``` + +**Client Components** need the `'use client'` directive: + +```tsx +'use client' +import { useState } from 'react' +import { useAuth } from '@payloadcms/ui' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + const { user } = useAuth() + + return ( + + ) +} +``` + +### Using Hooks (Client Components Only) + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Document info (id, collection, etc.) + useField, // Field value and setter + useForm, // Form state + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +### Collection/Global Components + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/SaveDraft', + PublishButton: '/components/Publish', + }, + + // List view + list: { + Header: '/components/ListHeader', + beforeList: ['/components/BulkActions'], + afterList: ['/components/ListFooter'], + }, + }, + }, +} +``` + +### Field Components + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + // Edit view field + Field: '/components/StatusField', + // List view cell + Cell: '/components/StatusCell', + // Field label + Label: '/components/StatusLabel', + // Field description + Description: '/components/StatusDescription', + // Error message + Error: '/components/StatusError', + }, + }, +} +``` + +**UI Field** (presentational only, no data): + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +### Performance Best Practices + +1. **Import correctly:** + + - Admin Panel: `import { Button } from '@payloadcms/ui'` + - Frontend: `import { Button } from '@payloadcms/ui/elements/Button'` + +2. **Optimize re-renders:** + + ```tsx + // ❌ BAD: Re-renders on every form change + const { fields } = useForm() + + // ✅ GOOD: Only re-renders when specific field changes + const value = useFormFields(([fields]) => fields[path]) + ``` + +3. **Prefer Server Components** - Only use Client Components when you need: + + - State (useState, useReducer) + - Effects (useEffect) + - Event handlers (onClick, onChange) + - Browser APIs (localStorage, window) + +4. **Minimize serialized props** - Server Components serialize props sent to client + +### Styling Components + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Content
+} +``` + +```scss +// Use Payload's CSS variables +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} + +// Import Payload's SCSS library +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +### Type Safety + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, + SelectFieldServerComponent, + // ... etc +} from 'payload' + +export const MyField: TextFieldClientComponent = (props) => { + // Fully typed props +} +``` + +### Import Map + +Payload auto-generates `app/(payload)/admin/importMap.js` to resolve component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Set custom location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Custom Endpoints + +```typescript +import type { Endpoint } from 'payload' +import { APIError } from 'payload' + +// Always check authentication +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} + +// Route parameters +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Drafts & Versions + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} + +// Create draft +await payload.create({ + collection: 'pages', + data: { title: 'Draft Page' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft if available +}) +``` + +## Field Type Guards + +```typescript +import { + fieldAffectsData, + fieldHasSubFields, + fieldIsArrayType, + fieldIsBlockType, + fieldSupportsMany, + fieldHasMaxDepth, +} from 'payload' + +function processField(field: Field) { + // Check if field stores data + if (fieldAffectsData(field)) { + console.log(field.name) // Safe to access + } + + // Check if field has nested fields + if (fieldHasSubFields(field)) { + field.fields.forEach(processField) // Safe to access + } + + // Check field type + if (fieldIsArrayType(field)) { + console.log(field.minRows, field.maxRows) + } + + // Check capabilities + if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') + } +} +``` + +## Plugins + +### Using Plugins + +```typescript +import { seoPlugin } from '@payloadcms/plugin-seo' +import { redirectsPlugin } from '@payloadcms/plugin-redirects' + +export default buildConfig({ + plugins: [ + seoPlugin({ + collections: ['posts', 'pages'], + }), + redirectsPlugin({ + collections: ['pages'], + }), + ], +}) +``` + +### Creating Plugins + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + collections?: string[] + enabled?: boolean +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...collection.fields, { name: 'pluginField', type: 'text' }], + } + } + return collection + }), + }) +``` + +## Best Practices + +### Security + +1. Always set `overrideAccess: false` when passing `user` to Local API +2. Field-level access only returns boolean (no query constraints) +3. Default to restrictive access, gradually add permissions +4. Never trust client-provided data +5. Use `saveToJWT: true` for roles to avoid database lookups + +### Performance + +1. Index frequently queried fields +2. Use `select` to limit returned fields +3. Set `maxDepth` on relationships to prevent over-fetching +4. Use query constraints over async operations in access control +5. Cache expensive operations in `req.context` + +### Data Integrity + +1. Always pass `req` to nested operations in hooks +2. Use context flags to prevent infinite hook loops +3. Enable transactions for MongoDB (requires replica set) and Postgres +4. Use `beforeValidate` for data formatting +5. Use `beforeChange` for business logic + +### Type Safety + +1. Run `generate:types` after schema changes +2. Import types from generated `payload-types.ts` +3. Type your user object: `import type { User } from '@/payload-types'` +4. Use `as const` for field options +5. Use field type guards for runtime type checking + +### Organization + +1. Keep collections in separate files +2. Extract access control to `access/` directory +3. Extract hooks to `hooks/` directory +4. Use reusable field factories for common patterns +5. Document complex access control with comments + +## Common Gotchas + +1. **Local API Default**: Access control bypassed unless `overrideAccess: false` +2. **Transaction Safety**: Missing `req` in nested operations breaks atomicity +3. **Hook Loops**: Operations in hooks can trigger the same hooks +4. **Field Access**: Cannot use query constraints, only boolean +5. **Relationship Depth**: Default depth is 2, set to 0 for IDs only +6. **Draft Status**: `_status` field auto-injected when drafts enabled +7. **Type Generation**: Types not updated until `generate:types` runs +8. **MongoDB Transactions**: Require replica set configuration +9. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +10. **Point Fields**: Not supported in SQLite + +## Additional Context Files + +For deeper exploration of specific topics, refer to the context files located in `.cursor/rules/`: + +### Available Context Files + +1. **`payload-overview.md`** - High-level architecture and core concepts + + - Payload structure and initialization + - Configuration fundamentals + - Database adapters overview + +2. **`security-critical.md`** - Critical security patterns (⚠️ IMPORTANT) + + - Local API access control + - Transaction safety in hooks + - Preventing infinite hook loops + +3. **`collections.md`** - Collection configurations + + - Basic collection patterns + - Auth collections with RBAC + - Upload collections + - Drafts and versioning + - Globals + +4. **`fields.md`** - Field types and patterns + + - All field types with examples + - Conditional fields + - Virtual fields + - Field validation + - Common field patterns + +5. **`field-type-guards.md`** - TypeScript field type utilities + + - Field type checking utilities + - Safe type narrowing + - Runtime field validation + +6. **`access-control.md`** - Permission patterns + + - Collection-level access + - Field-level access + - Row-level security + - RBAC patterns + - Multi-tenant access control + +7. **`access-control-advanced.md`** - Complex access patterns + + - Nested document access + - Cross-collection permissions + - Dynamic role hierarchies + - Performance optimization + +8. **`hooks.md`** - Lifecycle hooks + + - Collection hooks + - Field hooks + - Hook context patterns + - Common hook recipes + +9. **`queries.md`** - Database operations + + - Local API usage + - Query operators + - Complex queries with AND/OR + - Performance optimization + +10. **`endpoints.md`** - Custom API endpoints + + - REST endpoint patterns + - Authentication in endpoints + - Error handling + - Route parameters + +11. **`adapters.md`** - Database and storage adapters + + - MongoDB, PostgreSQL, SQLite patterns + - Storage adapter usage (S3, Azure, GCS, etc.) + - Custom adapter development + +12. **`plugin-development.md`** - Creating plugins + + - Plugin architecture + - Modifying configuration + - Plugin hooks + - Best practices + +13. **`components.md`** - Custom Components + + - Component types (Root, Collection, Global, Field) + - Server vs Client Components + - Component paths and definition + - Default and custom props + - Using hooks + - Performance best practices + - Styling components + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/with-vercel-mongodb/package.json b/templates/with-vercel-mongodb/package.json index d5077177e26..b23cf2101f4 100644 --- a/templates/with-vercel-mongodb/package.json +++ b/templates/with-vercel-mongodb/package.json @@ -18,15 +18,15 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/db-mongodb": "3.63.0", - "@payloadcms/next": "3.63.0", - "@payloadcms/richtext-lexical": "3.63.0", - "@payloadcms/storage-vercel-blob": "3.63.0", - "@payloadcms/ui": "3.63.0", + "@payloadcms/db-mongodb": "3.68.5", + "@payloadcms/next": "3.68.5", + "@payloadcms/richtext-lexical": "3.68.5", + "@payloadcms/storage-vercel-blob": "3.68.5", + "@payloadcms/ui": "3.68.5", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.63.0", + "payload": "3.68.5", "react": "19.2.1", "react-dom": "19.2.1" }, @@ -48,7 +48,7 @@ "vite-tsconfig-paths": "5.1.4", "vitest": "3.2.3" }, - "packageManager": "pnpm@10.20.0", + "packageManager": "pnpm@10.26.0", "engines": { "node": "^18.20.2 || >=20.9.0" }, diff --git a/templates/with-vercel-mongodb/src/payload-types.ts b/templates/with-vercel-mongodb/src/payload-types.ts index ec118e0473e..7c24a0d57f3 100644 --- a/templates/with-vercel-mongodb/src/payload-types.ts +++ b/templates/with-vercel-mongodb/src/payload-types.ts @@ -86,6 +86,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: {}; globalsSelect: {}; locale: null; diff --git a/templates/with-vercel-mongodb/src/payload.config.ts b/templates/with-vercel-mongodb/src/payload.config.ts index 990546d2a8f..8aefe6a38f2 100644 --- a/templates/with-vercel-mongodb/src/payload.config.ts +++ b/templates/with-vercel-mongodb/src/payload.config.ts @@ -1,12 +1,11 @@ -import { vercelBlobStorage } from '@payloadcms/storage-vercel-blob' import { mongooseAdapter } from '@payloadcms/db-mongodb' import { lexicalEditor } from '@payloadcms/richtext-lexical' import path from 'path' import { buildConfig } from 'payload' import { fileURLToPath } from 'url' - import { Users } from './collections/Users' import { Media } from './collections/Media' +import { vercelBlobStorage } from '@payloadcms/storage-vercel-blob' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) diff --git a/templates/with-vercel-postgres/.cursor/rules/access-control-advanced.md b/templates/with-vercel-postgres/.cursor/rules/access-control-advanced.md new file mode 100644 index 00000000000..68f52fd1287 --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/access-control-advanced.md @@ -0,0 +1,519 @@ +--- +title: Access Control - Advanced Patterns +description: Context-aware, time-based, subscription-based access, factory functions, templates +tags: [payload, access-control, security, advanced, performance] +priority: high +--- + +# Advanced Access Control Patterns + +Advanced access control patterns including context-aware access, time-based restrictions, factory functions, and production templates. + +## Context-Aware Access Patterns + +### Locale-Specific Access + +```typescript +import type { Access } from 'payload' + +export const localeSpecificAccess: Access = ({ req: { user, locale } }) => { + // Authenticated users can access all locales + if (user) return true + + // Public users can only access English content + if (locale === 'en') return true + + return false +} +``` + +### Device-Specific Access + +```typescript +export const mobileOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return /mobile|android|iphone/i.test(userAgent) +} + +export const desktopOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return !/mobile|android|iphone/i.test(userAgent) +} +``` + +### IP-Based Access + +```typescript +export const restrictedIpAccess = (allowedIps: string[]): Access => { + return ({ req: { headers } }) => { + const ip = headers?.get('x-forwarded-for') || headers?.get('x-real-ip') + return allowedIps.includes(ip || '') + } +} + +// Usage +const internalIps = ['192.168.1.0/24', '10.0.0.5'] + +export const InternalDocs: CollectionConfig = { + slug: 'internal-docs', + access: { + read: restrictedIpAccess(internalIps), + }, +} +``` + +## Time-Based Access Patterns + +### Today's Records Only + +```typescript +export const todayOnlyAccess: Access = ({ req: { user } }) => { + if (!user) return false + + const now = new Date() + const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000) + + return { + createdAt: { + greater_than_equal: startOfDay.toISOString(), + less_than: endOfDay.toISOString(), + }, + } +} +``` + +### Recent Records (Last N Days) + +```typescript +export const recentRecordsAccess = (days: number): Access => { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - days) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} + +// Usage: Users see only last 30 days, admins see all +export const Logs: CollectionConfig = { + slug: 'logs', + access: { + read: recentRecordsAccess(30), + }, +} +``` + +### Scheduled Content (Publish Date Range) + +```typescript +export const scheduledContentAccess: Access = ({ req: { user } }) => { + // Editors see all content + if (user?.roles?.includes('admin') || user?.roles?.includes('editor')) { + return true + } + + const now = new Date().toISOString() + + // Public sees only content within publish window + return { + and: [ + { publishDate: { less_than_equal: now } }, + { + or: [{ unpublishDate: { exists: false } }, { unpublishDate: { greater_than: now } }], + }, + ], + } +} +``` + +## Subscription-Based Access + +### Active Subscription Required + +```typescript +export const activeSubscriptionAccess: Access = async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + return subscription?.status === 'active' + } catch { + return false + } +} +``` + +### Subscription Tier-Based Access + +```typescript +export const tierBasedAccess = (requiredTier: string): Access => { + const tierHierarchy = ['free', 'basic', 'pro', 'enterprise'] + + return async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + if (subscription?.status !== 'active') return false + + const userTierIndex = tierHierarchy.indexOf(subscription.tier) + const requiredTierIndex = tierHierarchy.indexOf(requiredTier) + + return userTierIndex >= requiredTierIndex + } catch { + return false + } + } +} + +// Usage +export const EnterpriseFeatures: CollectionConfig = { + slug: 'enterprise-features', + access: { + read: tierBasedAccess('enterprise'), + }, +} +``` + +## Factory Functions + +### createRoleBasedAccess + +```typescript +export function createRoleBasedAccess(roles: string[]): Access { + return ({ req: { user } }) => { + if (!user) return false + return roles.some((role) => user.roles?.includes(role)) + } +} + +// Usage +const adminOrEditor = createRoleBasedAccess(['admin', 'editor']) +const moderatorAccess = createRoleBasedAccess(['admin', 'moderator']) +``` + +### createOrgScopedAccess + +```typescript +export function createOrgScopedAccess(allowAdmin = true): Access { + return ({ req: { user } }) => { + if (!user) return false + if (allowAdmin && user.roles?.includes('admin')) return true + + return { + organizationId: { in: user.organizationIds || [] }, + } + } +} + +// Usage +const orgScoped = createOrgScopedAccess() // Admins bypass +const strictOrgScoped = createOrgScopedAccess(false) // Admins also scoped +``` + +### createTeamBasedAccess + +```typescript +export function createTeamBasedAccess(teamField = 'teamId'): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + [teamField]: { in: user.teamIds || [] }, + } + } +} +``` + +### createTimeLimitedAccess + +```typescript +export function createTimeLimitedAccess(daysAccess: number): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - daysAccess) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} +``` + +## Configuration Templates + +### Public + Authenticated Collection + +```typescript +export const PublicAuthCollection: CollectionConfig = { + slug: 'posts', + access: { + // Only admins/editors can create + create: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Authenticated users see all, public sees only published + read: ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } + }, + + // Only admins/editors can update + update: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Only admins can delete + delete: ({ req: { user } }) => { + return user?.roles?.includes('admin') || false + }, + }, + versions: { + drafts: true, + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'content', type: 'richText', required: true }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], +} +``` + +### Self-Service Collection + +```typescript +export const SelfServiceCollection: CollectionConfig = { + slug: 'users', + auth: true, + access: { + // Admins can create users + create: ({ req: { user } }) => user?.roles?.includes('admin') || false, + + // Anyone can read user profiles + read: () => true, + + // Users can update self, admins can update anyone + update: ({ req: { user }, id }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + return user.id === id + }, + + // Only admins can delete + delete: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + fields: [ + { name: 'name', type: 'text', required: true }, + { name: 'email', type: 'email', required: true }, + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + access: { + // Only admins can read/update roles + read: ({ req: { user } }) => user?.roles?.includes('admin') || false, + update: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + }, + ], +} +``` + +## Performance Considerations + +### Avoid Async Operations in Hot Paths + +```typescript +// ❌ Slow: Multiple sequential async calls +export const slowAccess: Access = async ({ req: { user } }) => { + const org = await req.payload.findByID({ collection: 'orgs', id: user.orgId }) + const team = await req.payload.findByID({ collection: 'teams', id: user.teamId }) + const subscription = await req.payload.findByID({ collection: 'subs', id: user.subId }) + + return org.active && team.active && subscription.active +} + +// ✅ Fast: Use query constraints or cache in context +export const fastAccess: Access = ({ req: { user, context } }) => { + // Cache expensive lookups + if (!context.orgStatus) { + context.orgStatus = checkOrgStatus(user.orgId) + } + + return context.orgStatus +} +``` + +### Query Constraint Optimization + +```typescript +// ❌ Avoid: Non-indexed fields in constraints +export const slowQuery: Access = () => ({ + 'metadata.internalCode': { equals: 'ABC123' }, // Slow if not indexed +}) + +// ✅ Better: Use indexed fields +export const fastQuery: Access = () => ({ + status: { equals: 'active' }, // Indexed field + organizationId: { in: ['org1', 'org2'] }, // Indexed field +}) +``` + +### Field Access on Large Arrays + +```typescript +// ❌ Slow: Complex access on array fields +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: async ({ req }) => { + // Async call runs for EVERY array item + const result = await expensiveCheck() + return result + }, + }, + }, + ], +} + +// ✅ Fast: Simple checks or cache result +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: ({ req: { user }, context }) => { + // Cache once, reuse for all items + if (context.canReadSecret === undefined) { + context.canReadSecret = user?.roles?.includes('admin') + } + return context.canReadSecret + }, + }, + }, + ], +} +``` + +### Avoid N+1 Queries + +```typescript +// ❌ N+1 Problem: Query per access check +export const n1Access: Access = async ({ req, id }) => { + // Runs for EACH document in list + const doc = await req.payload.findByID({ collection: 'docs', id }) + return doc.isPublic +} + +// ✅ Better: Use query constraint to filter at DB level +export const efficientAccess: Access = () => { + return { isPublic: { equals: true } } +} +``` + +## Debugging Tips + +### Log Access Check Execution + +```typescript +export const debugAccess: Access = ({ req: { user }, id }) => { + console.log('Access check:', { + userId: user?.id, + userRoles: user?.roles, + docId: id, + timestamp: new Date().toISOString(), + }) + return true +} +``` + +### Verify Arguments Availability + +```typescript +export const checkArgsAccess: Access = (args) => { + console.log('Available arguments:', { + hasReq: 'req' in args, + hasUser: args.req?.user ? 'yes' : 'no', + hasId: args.id ? 'provided' : 'undefined', + hasData: args.data ? 'provided' : 'undefined', + }) + return true +} +``` + +### Test Access Without User + +```typescript +// In test/development +const testAccess = await payload.find({ + collection: 'posts', + overrideAccess: false, // Enforce access control + user: undefined, // Simulate no user +}) + +console.log('Public access result:', testAccess.docs.length) +``` + +## Best Practices + +1. **Default Deny**: Start with restrictive access, gradually add permissions +2. **Type Guards**: Use TypeScript for user type safety +3. **Validate Data**: Never trust frontend-provided IDs or data +4. **Async for Critical Checks**: Use async operations for important security decisions +5. **Consistent Logic**: Apply same rules at field and collection levels +6. **Test Edge Cases**: Test with no user, wrong user, admin user scenarios +7. **Monitor Access**: Log failed access attempts for security review +8. **Regular Audit**: Review access rules quarterly or after major changes +9. **Cache Wisely**: Use `req.context` for expensive operations +10. **Document Intent**: Add comments explaining complex access rules +11. **Avoid Secrets in Client**: Never expose sensitive logic to client-side +12. **Handle Errors Gracefully**: Access functions should return `false` on error, not throw +13. **Test Local API**: Remember to set `overrideAccess: false` when testing +14. **Consider Performance**: Measure impact of async operations +15. **Principle of Least Privilege**: Grant minimum access required + +## Performance Summary + +**Minimize Async Operations**: Use query constraints over async lookups when possible + +**Cache Expensive Checks**: Store results in `req.context` for reuse + +**Index Query Fields**: Ensure fields in query constraints are indexed + +**Avoid Complex Logic in Array Fields**: Simple boolean checks preferred + +**Use Query Constraints**: Let database filter rather than loading all records diff --git a/templates/with-vercel-postgres/.cursor/rules/access-control.md b/templates/with-vercel-postgres/.cursor/rules/access-control.md new file mode 100644 index 00000000000..7b9a0a4ba5c --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/access-control.md @@ -0,0 +1,225 @@ +--- +title: Access Control +description: Collection, field, and global access control patterns +tags: [payload, access-control, security, permissions, rbac] +--- + +# Payload CMS Access Control + +## Access Control Layers + +1. **Collection-Level**: Controls operations on entire documents (create, read, update, delete, admin) +2. **Field-Level**: Controls access to individual fields (create, read, update) +3. **Global-Level**: Controls access to global documents (read, update) + +## Collection Access Control + +```typescript +import type { Access } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + // Boolean: Only authenticated users can create + create: ({ req: { user } }) => Boolean(user), + + // Query constraint: Public sees published, users see all + read: ({ req: { user } }) => { + if (user) return true + return { status: { equals: 'published' } } + }, + + // User-specific: Admins or document owner + update: ({ req: { user }, id }) => { + if (user?.roles?.includes('admin')) return true + return { author: { equals: user?.id } } + }, + + // Async: Check related data + delete: async ({ req, id }) => { + const hasComments = await req.payload.count({ + collection: 'comments', + where: { post: { equals: id } }, + }) + return hasComments === 0 + }, + }, +} +``` + +## Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Row-Level Security + +```typescript +// Organization-scoped access +export const organizationScoped: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + + // Users see only their organization's data + return { + organization: { + equals: user?.organization, + }, + } +} + +// Team-based access +export const teamMemberAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + 'team.members': { + contains: user.id, + }, + } +} +``` + +## Field Access Control + +**Field access ONLY returns boolean** (no query constraints). + +```typescript +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +## RBAC Pattern + +Payload does NOT provide a roles system by default. Add a `roles` field to your auth collection: + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Multi-Tenant Access Control + +```typescript +interface User { + id: string + tenantId: string + roles?: string[] +} + +const tenantAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('super-admin')) return true + + return { + tenant: { + equals: (user as User).tenantId, + }, + } +} + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + create: tenantAccess, + read: tenantAccess, + update: tenantAccess, + delete: tenantAccess, + }, + fields: [ + { + name: 'tenant', + type: 'text', + required: true, + access: { + update: ({ req: { user } }) => user?.roles?.includes('super-admin'), + }, + hooks: { + beforeChange: [ + ({ req, operation, value }) => { + if (operation === 'create' && !value) { + return (req.user as User)?.tenantId + } + return value + }, + ], + }, + }, + ], +} +``` + +## Important Notes + +1. **Local API Default**: Access control is **skipped by default** in Local API (`overrideAccess: true`). When passing a `user` parameter, you must set `overrideAccess: false`: + +```typescript +// ❌ WRONG: Passes user but bypasses access control +await payload.find({ + collection: 'posts', + user: someUser, +}) + +// ✅ CORRECT: Respects the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // Required to enforce access control +}) +``` + +2. **Field Access Limitations**: Field-level access does NOT support query constraints - only boolean returns. + +3. **Admin Panel Visibility**: The `admin` access control determines if a collection appears in the admin panel for a user. diff --git a/templates/with-vercel-postgres/.cursor/rules/adapters.md b/templates/with-vercel-postgres/.cursor/rules/adapters.md new file mode 100644 index 00000000000..49b8b3367fc --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/adapters.md @@ -0,0 +1,209 @@ +--- +title: Database Adapters & Transactions +description: Database adapters, storage, email, and transaction patterns +tags: [payload, database, mongodb, postgres, sqlite, transactions] +--- + +# Payload CMS Adapters + +## Database Adapters + +### MongoDB + +```typescript +import { mongooseAdapter } from '@payloadcms/db-mongodb' + +export default buildConfig({ + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +### Postgres + +```typescript +import { postgresAdapter } from '@payloadcms/db-postgres' + +export default buildConfig({ + db: postgresAdapter({ + pool: { + connectionString: process.env.DATABASE_URI, + }, + push: false, // Don't auto-push schema changes + migrationDir: './migrations', + }), +}) +``` + +### SQLite + +```typescript +import { sqliteAdapter } from '@payloadcms/db-sqlite' + +export default buildConfig({ + db: sqliteAdapter({ + client: { + url: 'file:./payload.db', + }, + transactionOptions: {}, // Enable transactions (disabled by default) + }), +}) +``` + +## Transactions + +Payload automatically uses transactions for all-or-nothing database operations. + +### Threading req Through Operations + +**CRITICAL**: When performing nested operations in hooks, always pass `req` to maintain transaction context. + +```typescript +// ✅ CORRECT: Thread req through nested operations +const resaveChildren: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + // Find children - pass req + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + req, // Maintains transaction context + }) + + // Update each child - pass req + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + req, // Same transaction as parent operation + }) + } +} + +// ❌ WRONG: Missing req breaks transaction +const brokenHook: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + // Missing req - separate transaction or no transaction + }) + + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + // Missing req - if parent operation fails, these updates persist + }) + } +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +### Manual Transaction Control + +```typescript +const transactionID = await payload.db.beginTransaction() +try { + await payload.create({ + collection: 'orders', + data: orderData, + req: { transactionID }, + }) + await payload.update({ + collection: 'inventory', + id: itemId, + data: { stock: newStock }, + req: { transactionID }, + }) + await payload.db.commitTransaction(transactionID) +} catch (error) { + await payload.db.rollbackTransaction(transactionID) + throw error +} +``` + +## Storage Adapters + +Available storage adapters: + +- **@payloadcms/storage-s3** - AWS S3 +- **@payloadcms/storage-azure** - Azure Blob Storage +- **@payloadcms/storage-gcs** - Google Cloud Storage +- **@payloadcms/storage-r2** - Cloudflare R2 +- **@payloadcms/storage-vercel-blob** - Vercel Blob +- **@payloadcms/storage-uploadthing** - Uploadthing + +### AWS S3 + +```typescript +import { s3Storage } from '@payloadcms/storage-s3' + +export default buildConfig({ + plugins: [ + s3Storage({ + collections: { + media: true, + }, + bucket: process.env.S3_BUCKET, + config: { + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + region: process.env.S3_REGION, + }, + }), + ], +}) +``` + +## Email Adapters + +### Nodemailer (SMTP) + +```typescript +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' + +export default buildConfig({ + email: nodemailerAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + transportOptions: { + host: process.env.SMTP_HOST, + port: 587, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }, + }), +}) +``` + +### Resend + +```typescript +import { resendAdapter } from '@payloadcms/email-resend' + +export default buildConfig({ + email: resendAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + apiKey: process.env.RESEND_API_KEY, + }), +}) +``` + +## Important Notes + +1. **MongoDB Transactions**: Require replica set configuration +2. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +3. **Pass req**: Always pass `req` to nested operations in hooks for transaction safety +4. **Point Fields**: Not supported in SQLite diff --git a/templates/with-vercel-postgres/.cursor/rules/collections.md b/templates/with-vercel-postgres/.cursor/rules/collections.md new file mode 100644 index 00000000000..af625108e60 --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/collections.md @@ -0,0 +1,171 @@ +--- +title: Collections +description: Collection configurations and patterns +tags: [payload, collections, auth, upload, drafts] +--- + +# Payload CMS Collections + +## Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +## Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Upload Collection + +```typescript +export const Media: CollectionConfig = { + slug: 'media', + upload: { + staticDir: 'media', + mimeTypes: ['image/*'], + imageSizes: [ + { + name: 'thumbnail', + width: 400, + height: 300, + position: 'centre', + }, + { + name: 'card', + width: 768, + height: 1024, + }, + ], + adminThumbnail: 'thumbnail', + focalPoint: true, + crop: true, + }, + access: { + read: () => true, + }, + fields: [ + { + name: 'alt', + type: 'text', + required: true, + }, + ], +} +``` + +## Versioning & Drafts + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} +``` + +### Draft API Usage + +```typescript +// Create draft +await payload.create({ + collection: 'posts', + data: { title: 'Draft Post' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft version if exists +}) +``` + +## Globals + +Globals are single-instance documents (not collections). + +```typescript +import type { GlobalConfig } from 'payload' + +export const Header: GlobalConfig = { + slug: 'header', + label: 'Header', + admin: { + group: 'Settings', + }, + fields: [ + { + name: 'logo', + type: 'upload', + relationTo: 'media', + required: true, + }, + { + name: 'nav', + type: 'array', + maxRows: 8, + fields: [ + { + name: 'link', + type: 'relationship', + relationTo: 'pages', + }, + { + name: 'label', + type: 'text', + }, + ], + }, + ], +} +``` diff --git a/templates/with-vercel-postgres/.cursor/rules/components.md b/templates/with-vercel-postgres/.cursor/rules/components.md new file mode 100644 index 00000000000..8610b8d7b33 --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/components.md @@ -0,0 +1,794 @@ +# Custom Components in Payload CMS + +Custom Components allow you to fully customize the Admin Panel by swapping in your own React components. You can replace nearly every part of the interface or add entirely new functionality. + +## Component Types + +There are four main types of Custom Components: + +1. **Root Components** - Affect the Admin Panel globally (logo, nav, header) +2. **Collection Components** - Specific to collection views +3. **Global Components** - Specific to global document views +4. **Field Components** - Custom field UI and cells + +## Defining Custom Components + +### Component Paths + +Components are defined using file paths (not direct imports) to keep the config lightweight and Node.js compatible. + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + logout: { + Button: '/src/components/Logout#MyComponent', // Named export + }, + Nav: '/src/components/Nav', // Default export + }, + }, +}) +``` + +**Component Path Rules:** + +1. Paths are relative to project root (or `config.admin.importMap.baseDir`) +2. For **named exports**: append `#ExportName` or use `exportName` property +3. For **default exports**: no suffix needed +4. File extensions can be omitted + +### Component Config Object + +Instead of a string path, you can pass a config object: + +```typescript +{ + logout: { + Button: { + path: '/src/components/Logout', + exportName: 'MyComponent', + clientProps: { customProp: 'value' }, + serverProps: { asyncData: someData }, + }, + }, +} +``` + +**Config Properties:** + +| Property | Description | +| ------------- | ----------------------------------------------------- | +| `path` | File path to component (named exports via `#`) | +| `exportName` | Named export (alternative to `#` in path) | +| `clientProps` | Props for Client Components (must be serializable) | +| `serverProps` | Props for Server Components (can be non-serializable) | + +### Setting Base Directory + +```typescript +import path from 'path' +import { fileURLToPath } from 'node:url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), // Set base directory + }, + components: { + Nav: '/components/Nav', // Now relative to src/ + }, + }, +}) +``` + +## Server vs Client Components + +**All components are React Server Components by default.** + +### Server Components (Default) + +Can use Local API directly, perform async operations, and access full Payload instance. + +```tsx +import React from 'react' +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const page = await payload.findByID({ + collection: 'pages', + id: '123', + }) + + return

{page.title}

+} + +export default MyServerComponent +``` + +### Client Components + +Use the `'use client'` directive for interactivity, hooks, state, etc. + +```tsx +'use client' +import React, { useState } from 'react' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + + return +} +``` + +**Important:** Client Components cannot receive non-serializable props (functions, class instances, etc.). Payload automatically strips these when passing to client components. + +## Default Props + +All Custom Components receive these props by default: + +| Prop | Description | Type | +| --------- | ---------------------------------------- | --------- | +| `payload` | Payload instance (Local API access) | `Payload` | +| `i18n` | Internationalization object | `I18n` | +| `locale` | Current locale (if localization enabled) | `string` | + +**Server Component Example:** + +```tsx +async function MyComponent({ payload, i18n, locale }) { + const data = await payload.find({ + collection: 'posts', + locale, + }) + + return
{data.docs.length} posts
+} +``` + +**Client Component Example:** + +```tsx +'use client' +import { usePayload, useLocale, useTranslation } from '@payloadcms/ui' + +export function MyComponent() { + // Access via hooks in client components + const { getLocal, getByID } = usePayload() + const locale = useLocale() + const { t, i18n } = useTranslation() + + return
{t('myKey')}
+} +``` + +## Custom Props + +Pass additional props using `clientProps` or `serverProps`: + +```typescript +{ + logout: { + Button: { + path: '/components/Logout', + clientProps: { + buttonText: 'Sign Out', + onLogout: () => console.log('Logged out'), + }, + }, + }, +} +``` + +Receive in component: + +```tsx +'use client' +export function Logout({ buttonText, onLogout }) { + return +} +``` + +## Root Components + +Root Components affect the entire Admin Panel. + +### Available Root Components + +| Component | Description | Config Path | +| ----------------- | -------------------------------- | ---------------------------------- | +| `Nav` | Entire navigation sidebar | `admin.components.Nav` | +| `graphics.Icon` | Small icon (used in nav) | `admin.components.graphics.Icon` | +| `graphics.Logo` | Full logo (used on login) | `admin.components.graphics.Logo` | +| `logout.Button` | Logout button | `admin.components.logout.Button` | +| `actions` | Header actions (array) | `admin.components.actions` | +| `header` | Above header (array) | `admin.components.header` | +| `beforeDashboard` | Before dashboard content (array) | `admin.components.beforeDashboard` | +| `afterDashboard` | After dashboard content (array) | `admin.components.afterDashboard` | +| `beforeLogin` | Before login form (array) | `admin.components.beforeLogin` | +| `afterLogin` | After login form (array) | `admin.components.afterLogin` | +| `beforeNavLinks` | Before nav links (array) | `admin.components.beforeNavLinks` | +| `afterNavLinks` | After nav links (array) | `admin.components.afterNavLinks` | +| `settingsMenu` | Settings menu items (array) | `admin.components.settingsMenu` | +| `providers` | Custom React Context providers | `admin.components.providers` | +| `views` | Custom views (dashboard, etc.) | `admin.components.views` | + +### Example: Custom Logo + +```typescript +export default buildConfig({ + admin: { + components: { + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + }, + }, +}) +``` + +```tsx +// components/Logo.tsx +export default function Logo() { + return My Brand +} +``` + +### Example: Header Actions + +```typescript +export default buildConfig({ + admin: { + components: { + actions: ['/components/ClearCacheButton', '/components/PreviewButton'], + }, + }, +}) +``` + +```tsx +// components/ClearCacheButton.tsx +'use client' +export default function ClearCacheButton() { + return ( + + ) +} +``` + +## Collection Components + +Collection Components are specific to a collection's views. + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view components + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/CustomSaveDraft', + PublishButton: '/components/CustomPublish', + }, + + // List view components + list: { + Header: '/components/PostsListHeader', + beforeList: ['/components/ListFilters'], + afterList: ['/components/ListFooter'], + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Global Components + +Similar to Collection Components but for Global documents. + +```typescript +import type { GlobalConfig } from 'payload' + +export const Settings: GlobalConfig = { + slug: 'settings', + admin: { + components: { + edit: { + PreviewButton: '/components/SettingsPreview', + SaveButton: '/components/SettingsSave', + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Field Components + +Customize how fields render in Edit and List views. + +### Field Component (Edit View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Field: '/components/StatusField', + }, + }, +} +``` + +```tsx +// components/StatusField.tsx +'use client' +import { useField } from '@payloadcms/ui' +import type { SelectFieldClientComponent } from 'payload' + +export const StatusField: SelectFieldClientComponent = ({ path, field }) => { + const { value, setValue } = useField({ path }) + + return ( +
+ + +
+ ) +} +``` + +### Cell Component (List View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Cell: '/components/StatusCell', + }, + }, +} +``` + +```tsx +// components/StatusCell.tsx +import type { SelectFieldCellComponent } from 'payload' + +export const StatusCell: SelectFieldCellComponent = ({ data, cellData }) => { + const isPublished = cellData === 'published' + + return ( + + {cellData} + + ) +} +``` + +### UI Field (Presentational Only) + +Special field type for adding custom UI without affecting data: + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +```tsx +// components/RefundButton.tsx +'use client' +import { useDocumentInfo } from '@payloadcms/ui' + +export default function RefundButton() { + const { id } = useDocumentInfo() + + return ( + + ) +} +``` + +## Using Hooks + +Payload provides many React hooks for Client Components: + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Current document info (id, slug, etc.) + useField, // Field value and setValue + useForm, // Form state and dispatch + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +**Important:** These hooks only work in Client Components within the Admin Panel context. + +## Accessing Payload Config + +**In Server Components:** + +```tsx +async function MyServerComponent({ payload }) { + const { config } = payload + return
{config.serverURL}
+} +``` + +**In Client Components:** + +```tsx +'use client' +import { useConfig } from '@payloadcms/ui' + +export function MyClientComponent() { + const { config } = useConfig() // Client-safe config + return
{config.serverURL}
+} +``` + +**Important:** Client Components receive a serializable version of the config (functions, validation, etc. are stripped). + +## Field Config Access + +**Server Component:** + +```tsx +import type { TextFieldServerComponent } from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = ({ field }) => { + return
Field name: {field.name}
+} +``` + +**Client Component:** + +```tsx +'use client' +import type { TextFieldClientComponent } from 'payload' + +export const MyFieldComponent: TextFieldClientComponent = ({ clientField }) => { + // clientField has non-serializable props removed + return
Field name: {clientField.name}
+} +``` + +## Translations (i18n) + +**Server Component:** + +```tsx +import { getTranslation } from '@payloadcms/translations' + +async function MyServerComponent({ i18n }) { + const translatedTitle = getTranslation(myTranslation, i18n) + return

{translatedTitle}

+} +``` + +**Client Component:** + +```tsx +'use client' +import { useTranslation } from '@payloadcms/ui' + +export function MyClientComponent() { + const { t, i18n } = useTranslation() + + return ( +
+

{t('namespace:key', { variable: 'value' })}

+

Language: {i18n.language}

+
+ ) +} +``` + +## Styling Components + +### Using CSS Variables + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Custom Component
+} +``` + +```scss +// styles.scss +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} +``` + +### Importing Payload SCSS + +```scss +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +## Common Patterns + +### Conditional Field Visibility + +```tsx +'use client' +import { useFormFields } from '@payloadcms/ui' +import type { TextFieldClientComponent } from 'payload' + +export const ConditionalField: TextFieldClientComponent = ({ path }) => { + const showField = useFormFields(([fields]) => fields.enableFeature?.value) + + if (!showField) return null + + return +} +``` + +### Loading Data from API + +```tsx +'use client' +import { useState, useEffect } from 'react' + +export function DataLoader() { + const [data, setData] = useState(null) + + useEffect(() => { + fetch('/api/custom-data') + .then((res) => res.json()) + .then(setData) + }, []) + + return
{JSON.stringify(data)}
+} +``` + +### Using Local API in Server Components + +```tsx +import type { Payload } from 'payload' + +async function RelatedPosts({ payload, id }: { payload: Payload; id: string }) { + const post = await payload.findByID({ + collection: 'posts', + id, + depth: 0, + }) + + const related = await payload.find({ + collection: 'posts', + where: { + category: { equals: post.category }, + id: { not_equals: id }, + }, + limit: 5, + }) + + return ( +
+

Related Posts

+
    + {related.docs.map((doc) => ( +
  • {doc.title}
  • + ))} +
+
+ ) +} + +export default RelatedPosts +``` + +## Performance Best Practices + +### 1. Minimize Client Bundle Size + +```tsx +// ❌ BAD: Imports entire package +'use client' +import { Button } from '@payloadcms/ui' + +// ✅ GOOD: Tree-shakeable import for frontend +import { Button } from '@payloadcms/ui/elements/Button' +``` + +**Rule:** In Admin Panel UI, import from `@payloadcms/ui`. In frontend code, use specific paths. + +### 2. Optimize Re-renders + +```tsx +// ❌ BAD: Re-renders on every form change +'use client' +import { useForm } from '@payloadcms/ui' + +export function MyComponent() { + const { fields } = useForm() + // Re-renders on ANY field change +} + +// ✅ GOOD: Only re-renders when specific field changes +;('use client') +import { useFormFields } from '@payloadcms/ui' + +export function MyComponent({ path }) { + const value = useFormFields(([fields]) => fields[path]) + // Only re-renders when this field changes +} +``` + +### 3. Use Server Components When Possible + +```tsx +// ✅ GOOD: No JavaScript sent to client +async function PostCount({ payload }) { + const { totalDocs } = await payload.find({ + collection: 'posts', + limit: 0, + }) + + return

{totalDocs} posts

+} + +// Only use client components when you need: +// - State (useState, useReducer) +// - Effects (useEffect) +// - Event handlers (onClick, onChange) +// - Browser APIs (localStorage, window) +``` + +### 4. React Best Practices + +- Use React.memo() for expensive components +- Implement proper key props in lists +- Avoid inline function definitions in renders +- Use Suspense boundaries for async operations + +## Import Map + +Payload generates an import map at `app/(payload)/admin/importMap.js` that resolves all component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Override location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Type Safety + +Use Payload's TypeScript types for components: + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, +} from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = (props) => { + // Fully typed props +} +``` + +## Troubleshooting + +### "useConfig is undefined" or similar hook errors + +**Cause:** Dependency version mismatch between Payload packages. + +**Solution:** Pin all `@payloadcms/*` packages to the exact same version: + +```json +{ + "dependencies": { + "payload": "3.0.0", + "@payloadcms/ui": "3.0.0", + "@payloadcms/richtext-lexical": "3.0.0" + } +} +``` + +### Component not loading + +1. Check file path is correct (relative to baseDir) +2. Verify named export syntax: `/path/to/file#ExportName` +3. Run `payload generate:importmap` to regenerate +4. Check for TypeScript errors in component file + +## Resources + +- [Custom Components Docs](https://payloadcms.com/docs/custom-components/overview) +- [Root Components](https://payloadcms.com/docs/custom-components/root-components) +- [Custom Views](https://payloadcms.com/docs/custom-components/custom-views) +- [React Hooks](https://payloadcms.com/docs/admin/react-hooks) +- [Custom CSS](https://payloadcms.com/docs/admin/customizing-css) diff --git a/templates/with-vercel-postgres/.cursor/rules/endpoints.md b/templates/with-vercel-postgres/.cursor/rules/endpoints.md new file mode 100644 index 00000000000..8a2481dbe5d --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/endpoints.md @@ -0,0 +1,236 @@ +--- +title: Custom Endpoints +description: Custom REST API endpoints with authentication and helpers +tags: [payload, endpoints, api, routes, webhooks] +--- + +# Payload Custom Endpoints + +## Basic Endpoint Pattern + +Custom endpoints are **not authenticated by default**. Always check `req.user`. + +```typescript +import { APIError } from 'payload' +import type { Endpoint } from 'payload' + +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} +``` + +## Route Parameters + +```typescript +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Request Body Handling + +```typescript +// Manual JSON parsing +export const createEndpoint: Endpoint = { + path: '/create', + method: 'post', + handler: async (req) => { + const data = await req.json() + + const result = await req.payload.create({ + collection: 'posts', + data, + }) + + return Response.json(result) + }, +} + +// Using helper (handles JSON + files) +import { addDataAndFileToRequest } from 'payload' + +export const uploadEndpoint: Endpoint = { + path: '/upload', + method: 'post', + handler: async (req) => { + await addDataAndFileToRequest(req) + + // req.data contains parsed body + // req.file contains uploaded file (if multipart) + + const result = await req.payload.create({ + collection: 'media', + data: req.data, + file: req.file, + }) + + return Response.json(result) + }, +} +``` + +## Query Parameters + +```typescript +export const searchEndpoint: Endpoint = { + path: '/search', + method: 'get', + handler: async (req) => { + const url = new URL(req.url) + const query = url.searchParams.get('q') + const limit = parseInt(url.searchParams.get('limit') || '10') + + const results = await req.payload.find({ + collection: 'posts', + where: { + title: { + contains: query, + }, + }, + limit, + }) + + return Response.json(results) + }, +} +``` + +## CORS Headers + +```typescript +import { headersWithCors } from 'payload' + +export const corsEndpoint: Endpoint = { + path: '/public-data', + method: 'get', + handler: async (req) => { + const data = await fetchPublicData() + + return Response.json(data, { + headers: headersWithCors({ + headers: new Headers(), + req, + }), + }) + }, +} +``` + +## Error Handling + +```typescript +import { APIError } from 'payload' + +export const validateEndpoint: Endpoint = { + path: '/validate', + method: 'post', + handler: async (req) => { + const data = await req.json() + + if (!data.email) { + throw new APIError('Email is required', 400) + } + + return Response.json({ valid: true }) + }, +} +``` + +## Endpoint Placement + +### Collection Endpoints + +Mounted at `/api/{collection-slug}/{path}`. + +```typescript +export const Orders: CollectionConfig = { + slug: 'orders', + endpoints: [ + { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + // Available at: /api/orders/:id/tracking + const orderId = req.routeParams.id + return Response.json({ orderId }) + }, + }, + ], +} +``` + +### Global Endpoints + +Mounted at `/api/globals/{global-slug}/{path}`. + +```typescript +export const Settings: GlobalConfig = { + slug: 'settings', + endpoints: [ + { + path: '/clear-cache', + method: 'post', + handler: async (req) => { + // Available at: /api/globals/settings/clear-cache + await clearCache() + return Response.json({ message: 'Cache cleared' }) + }, + }, + ], +} +``` + +### Root Endpoints + +Mounted at `/api/{path}`. + +```typescript +export default buildConfig({ + endpoints: [ + { + path: '/hello', + method: 'get', + handler: () => { + // Available at: /api/hello + return Response.json({ message: 'Hello!' }) + }, + }, + ], +}) +``` + +## Best Practices + +1. **Always check authentication** - Custom endpoints are not authenticated by default +2. **Use `req.payload` for operations** - Ensures access control and hooks execute +3. **Use helpers for common tasks** - `addDataAndFileToRequest`, `headersWithCors` +4. **Throw `APIError` for errors** - Provides consistent error responses +5. **Return Web API `Response`** - Use `Response.json()` for consistent responses +6. **Validate input** - Check required fields, validate types +7. **Log errors** - Use `req.payload.logger` for debugging diff --git a/templates/with-vercel-postgres/.cursor/rules/field-type-guards.md b/templates/with-vercel-postgres/.cursor/rules/field-type-guards.md new file mode 100644 index 00000000000..3514ad44993 --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/field-type-guards.md @@ -0,0 +1,230 @@ +--- +title: Field Type Guards +description: Runtime field type checking and safe type narrowing +tags: [payload, typescript, type-guards, fields] +--- + +# Payload Field Type Guards + +Type guards for runtime field type checking and safe type narrowing. + +## Most Common Guards + +### fieldAffectsData + +**Most commonly used guard.** Checks if field stores data (has name and is not UI-only). + +```typescript +import { fieldAffectsData } from 'payload' + +function generateSchema(fields: Field[]) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + // Safe to access field.name + schema[field.name] = getFieldType(field) + } + }) +} + +// Filter data fields +const dataFields = fields.filter(fieldAffectsData) +``` + +### fieldHasSubFields + +Checks if field contains nested fields (group, array, row, or collapsible). + +```typescript +import { fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[]): void { + fields.forEach((field) => { + if (fieldHasSubFields(field)) { + // Safe to access field.fields + traverseFields(field.fields) + } + }) +} +``` + +### fieldIsArrayType + +Checks if field type is `'array'`. + +```typescript +import { fieldIsArrayType } from 'payload' + +if (fieldIsArrayType(field)) { + // field.type === 'array' + console.log(`Min rows: ${field.minRows}`) + console.log(`Max rows: ${field.maxRows}`) +} +``` + +## Capability Guards + +### fieldSupportsMany + +Checks if field can have multiple values (select, relationship, or upload with `hasMany`). + +```typescript +import { fieldSupportsMany } from 'payload' + +if (fieldSupportsMany(field)) { + // field.type is 'select' | 'relationship' | 'upload' + if (field.hasMany) { + console.log('Field accepts multiple values') + } +} +``` + +### fieldHasMaxDepth + +Checks if field is relationship/upload/join with numeric `maxDepth` property. + +```typescript +import { fieldHasMaxDepth } from 'payload' + +if (fieldHasMaxDepth(field)) { + // field.type is 'upload' | 'relationship' | 'join' + // AND field.maxDepth is number + const remainingDepth = field.maxDepth - currentDepth +} +``` + +### fieldIsVirtual + +Checks if field is virtual (computed or virtual relationship). + +```typescript +import { fieldIsVirtual } from 'payload' + +if (fieldIsVirtual(field)) { + // field.virtual is truthy + if (typeof field.virtual === 'string') { + console.log(`Virtual path: ${field.virtual}`) + } +} +``` + +## Type Checking Guards + +### fieldIsBlockType + +```typescript +import { fieldIsBlockType } from 'payload' + +if (fieldIsBlockType(field)) { + // field.type === 'blocks' + field.blocks.forEach((block) => { + console.log(`Block: ${block.slug}`) + }) +} +``` + +### fieldIsGroupType + +```typescript +import { fieldIsGroupType } from 'payload' + +if (fieldIsGroupType(field)) { + // field.type === 'group' + console.log(`Interface: ${field.interfaceName}`) +} +``` + +### fieldIsPresentationalOnly + +```typescript +import { fieldIsPresentationalOnly } from 'payload' + +if (fieldIsPresentationalOnly(field)) { + // field.type === 'ui' + // Skip in data operations, GraphQL schema, etc. + return +} +``` + +## Common Patterns + +### Recursive Field Traversal + +```typescript +import { fieldAffectsData, fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[], callback: (field: Field) => void) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + callback(field) + } + + if (fieldHasSubFields(field)) { + traverseFields(field.fields, callback) + } + }) +} +``` + +### Filter Data-Bearing Fields + +```typescript +import { fieldAffectsData, fieldIsPresentationalOnly, fieldIsHiddenOrDisabled } from 'payload' + +const dataFields = fields.filter( + (field) => + fieldAffectsData(field) && !fieldIsPresentationalOnly(field) && !fieldIsHiddenOrDisabled(field), +) +``` + +### Container Type Switching + +```typescript +import { fieldIsArrayType, fieldIsBlockType, fieldHasSubFields } from 'payload' + +if (fieldIsArrayType(field)) { + // Handle array-specific logic +} else if (fieldIsBlockType(field)) { + // Handle blocks-specific logic +} else if (fieldHasSubFields(field)) { + // Handle group/row/collapsible +} +``` + +### Safe Property Access + +```typescript +import { fieldSupportsMany, fieldHasMaxDepth } from 'payload' + +// With guard - safe access +if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') +} + +if (fieldHasMaxDepth(field)) { + const depth = field.maxDepth // TypeScript knows this is number +} +``` + +## All Available Guards + +| Type Guard | Checks For | Use When | +| --------------------------- | --------------------------------- | ---------------------------------------- | +| `fieldAffectsData` | Field stores data (has name) | Need to access field data or name | +| `fieldHasSubFields` | Field contains nested fields | Recursively traverse fields | +| `fieldIsArrayType` | Field is array type | Distinguish arrays from other containers | +| `fieldIsBlockType` | Field is blocks type | Handle blocks-specific logic | +| `fieldIsGroupType` | Field is group type | Handle group-specific logic | +| `fieldSupportsMany` | Field can have multiple values | Check for `hasMany` support | +| `fieldHasMaxDepth` | Field supports depth control | Control relationship/upload/join depth | +| `fieldIsPresentationalOnly` | Field is UI-only | Exclude from data operations | +| `fieldIsSidebar` | Field positioned in sidebar | Separate sidebar rendering | +| `fieldIsID` | Field name is 'id' | Special ID field handling | +| `fieldIsHiddenOrDisabled` | Field is hidden or disabled | Filter from UI operations | +| `fieldShouldBeLocalized` | Field needs localization | Proper locale table checks | +| `fieldIsVirtual` | Field is virtual | Skip in database transforms | +| `tabHasName` | Tab is named (stores data) | Distinguish named vs unnamed tabs | +| `groupHasName` | Group is named (stores data) | Distinguish named vs unnamed groups | +| `optionIsObject` | Option is `{label, value}` | Access option properties safely | +| `optionsAreObjects` | All options are objects | Batch option processing | +| `optionIsValue` | Option is string value | Handle string options | +| `valueIsValueWithRelation` | Value is polymorphic relationship | Handle polymorphic relationships | diff --git a/templates/with-vercel-postgres/.cursor/rules/fields.md b/templates/with-vercel-postgres/.cursor/rules/fields.md new file mode 100644 index 00000000000..8468e41f599 --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/fields.md @@ -0,0 +1,317 @@ +--- +title: Fields +description: Field types, patterns, and configurations +tags: [payload, fields, validation, conditional] +--- + +# Payload CMS Fields + +## Common Field Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## Field Types + +### Text Field + +```typescript +{ + name: 'title', + type: 'text', + required: true, + unique: true, + minLength: 5, + maxLength: 100, + index: true, + localized: true, + defaultValue: 'Default Title', + validate: (value) => Boolean(value) || 'Required', + admin: { + placeholder: 'Enter title...', + position: 'sidebar', + condition: (data) => data.showTitle === true, + }, +} +``` + +### Rich Text (Lexical) + +```typescript +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { HeadingFeature, LinkFeature } from '@payloadcms/richtext-lexical' + +{ + name: 'content', + type: 'richText', + required: true, + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + HeadingFeature({ + enabledHeadingSizes: ['h1', 'h2', 'h3'], + }), + LinkFeature({ + enabledCollections: ['posts', 'pages'], + }), + ], + }), +} +``` + +### Relationship + +```typescript +// Single relationship +{ + name: 'author', + type: 'relationship', + relationTo: 'users', + required: true, + maxDepth: 2, +} + +// Multiple relationships (hasMany) +{ + name: 'categories', + type: 'relationship', + relationTo: 'categories', + hasMany: true, + filterOptions: { + active: { equals: true }, + }, +} + +// Polymorphic relationship +{ + name: 'relatedContent', + type: 'relationship', + relationTo: ['posts', 'pages'], + hasMany: true, +} +``` + +### Array + +```typescript +{ + name: 'slides', + type: 'array', + minRows: 2, + maxRows: 10, + labels: { + singular: 'Slide', + plural: 'Slides', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'image', + type: 'upload', + relationTo: 'media', + }, + ], + admin: { + initCollapsed: true, + }, +} +``` + +### Blocks + +```typescript +import type { Block } from 'payload' + +const HeroBlock: Block = { + slug: 'hero', + interfaceName: 'HeroBlock', + fields: [ + { + name: 'heading', + type: 'text', + required: true, + }, + { + name: 'background', + type: 'upload', + relationTo: 'media', + }, + ], +} + +const ContentBlock: Block = { + slug: 'content', + fields: [ + { + name: 'text', + type: 'richText', + }, + ], +} + +{ + name: 'layout', + type: 'blocks', + blocks: [HeroBlock, ContentBlock], +} +``` + +### Select + +```typescript +{ + name: 'status', + type: 'select', + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + ], + defaultValue: 'draft', + required: true, +} + +// Multiple select +{ + name: 'tags', + type: 'select', + hasMany: true, + options: ['tech', 'news', 'sports'], +} +``` + +### Upload + +```typescript +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + required: true, + filterOptions: { + mimeType: { contains: 'image' }, + }, +} +``` + +### Point (Geolocation) + +```typescript +{ + name: 'location', + type: 'point', + label: 'Location', + required: true, +} + +// Query by distance +const nearbyLocations = await payload.find({ + collection: 'stores', + where: { + location: { + near: [10, 20], // [longitude, latitude] + maxDistance: 5000, // in meters + minDistance: 1000, + }, + }, +}) +``` + +### Join Fields (Reverse Relationships) + +```typescript +// From Users collection - show user's orders +{ + name: 'orders', + type: 'join', + collection: 'orders', + on: 'customer', // The field in 'orders' that references this user +} +``` + +### Tabs & Groups + +```typescript +// Tabs +{ + type: 'tabs', + tabs: [ + { + label: 'Content', + fields: [ + { name: 'title', type: 'text' }, + { name: 'body', type: 'richText' }, + ], + }, + { + label: 'SEO', + fields: [ + { name: 'metaTitle', type: 'text' }, + { name: 'metaDescription', type: 'textarea' }, + ], + }, + ], +} + +// Group (named) +{ + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], +} +``` + +## Validation + +```typescript +{ + name: 'email', + type: 'email', + validate: (value, { operation, data, siblingData }) => { + if (operation === 'create' && !value) { + return 'Email is required' + } + if (value && !value.includes('@')) { + return 'Invalid email format' + } + return true + }, +} +``` diff --git a/templates/with-vercel-postgres/.cursor/rules/hooks.md b/templates/with-vercel-postgres/.cursor/rules/hooks.md new file mode 100644 index 00000000000..1f168f9eaeb --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/hooks.md @@ -0,0 +1,175 @@ +--- +title: Hooks +description: Collection hooks, field hooks, and context patterns +tags: [payload, hooks, lifecycle, context] +--- + +# Payload CMS Hooks + +## Collection Hooks + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Field Hooks + +```typescript +import type { FieldHook } from 'payload' + +const beforeValidateHook: FieldHook = ({ value }) => { + return value.trim().toLowerCase() +} + +const afterReadHook: FieldHook = ({ value, req }) => { + // Hide email from non-admins + if (!req.user?.roles?.includes('admin')) { + return value.replace(/(.{2})(.*)(@.*)/, '$1***$3') + } + return value +} + +{ + name: 'email', + type: 'email', + hooks: { + beforeValidate: [beforeValidateHook], + afterRead: [afterReadHook], + }, +} +``` + +## Hook Context + +Share data between hooks or control hook behavior using request context: + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + beforeChange: [ + async ({ context }) => { + context.expensiveData = await fetchExpensiveData() + }, + ], + afterChange: [ + async ({ context, doc }) => { + // Reuse from previous hook + await processData(doc, context.expensiveData) + }, + ], + }, +} +``` + +## Next.js Revalidation Pattern + +```typescript +import type { CollectionAfterChangeHook } from 'payload' +import { revalidatePath } from 'next/cache' + +export const revalidatePage: CollectionAfterChangeHook = ({ + doc, + previousDoc, + req: { payload, context }, +}) => { + if (!context.disableRevalidate) { + if (doc._status === 'published') { + const path = doc.slug === 'home' ? '/' : `/${doc.slug}` + payload.logger.info(`Revalidating page at path: ${path}`) + revalidatePath(path) + } + + // Revalidate old path if unpublished + if (previousDoc?._status === 'published' && doc._status !== 'published') { + const oldPath = previousDoc.slug === 'home' ? '/' : `/${previousDoc.slug}` + revalidatePath(oldPath) + } + } + return doc +} +``` + +## Date Field Auto-Set + +```typescript +{ + name: 'publishedOn', + type: 'date', + hooks: { + beforeChange: [ + ({ siblingData, value }) => { + if (siblingData._status === 'published' && !value) { + return new Date() + } + return value + }, + ], + }, +} +``` + +## Best Practices + +- Use `beforeValidate` for data formatting +- Use `beforeChange` for business logic +- Use `afterChange` for side effects +- Use `afterRead` for computed fields +- Store expensive operations in `context` +- Pass `req` to nested operations for transaction safety +- Use context flags to prevent infinite loops diff --git a/templates/with-vercel-postgres/.cursor/rules/payload-overview.md b/templates/with-vercel-postgres/.cursor/rules/payload-overview.md new file mode 100644 index 00000000000..290c47822ab --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/payload-overview.md @@ -0,0 +1,126 @@ +--- +title: Payload CMS Overview +description: Core principles and quick reference for Payload CMS development +tags: [payload, overview, quickstart] +--- + +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Quick Reference + +| Task | Solution | +| --------------------- | ---------------------------------- | +| Auto-generate slugs | `slugField()` | +| Restrict by user | Access control with query | +| Local API user ops | `user` + `overrideAccess: false` | +| Draft/publish | `versions: { drafts: true }` | +| Computed fields | `virtual: true` with afterRead | +| Conditional fields | `admin.condition` | +| Custom validation | `validate` function | +| Filter relationships | `filterOptions` on field | +| Select fields | `select` parameter | +| Auto-set dates | beforeChange hook | +| Prevent loops | `req.context` check | +| Cascading deletes | beforeDelete hook | +| Geospatial queries | `point` field with `near`/`within` | +| Reverse relationships | `join` field type | +| Query relationships | Nested property syntax | +| Complex queries | AND/OR logic | +| Transactions | Pass `req` to operations | +| Background jobs | Jobs queue with tasks | +| Custom routes | Collection custom endpoints | +| Cloud storage | Storage adapter plugins | +| Multi-language | `localization` + `localized: true` | + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/with-vercel-postgres/.cursor/rules/plugin-development.md b/templates/with-vercel-postgres/.cursor/rules/plugin-development.md new file mode 100644 index 00000000000..d92bb12fb40 --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/plugin-development.md @@ -0,0 +1,323 @@ +--- +title: Plugin Development +description: Creating Payload CMS plugins with TypeScript patterns +tags: [payload, plugins, architecture, patterns] +--- + +# Payload Plugin Development + +## Plugin Architecture + +Plugins are functions that receive configuration options and return a function that transforms the Payload config: + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + enabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + // Transform config here + }) +``` + +**Key Pattern:** Double arrow function (currying) + +- First function: Accepts plugin options, returns plugin function +- Second function: Accepts Payload config, returns modified config + +## Adding Fields to Collections + +```typescript +export const seoPlugin = + (options: { collections?: string[] }): Plugin => + (config: Config): Config => { + const seoFields: Field[] = [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], + }, + ] + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...seoFields], + } + } + return collection + }), + } + } +``` + +## Adding New Collections + +```typescript +export const redirectsPlugin = + (options: { overrides?: Partial }): Plugin => + (config: Config): Config => { + const redirectsCollection: CollectionConfig = { + slug: 'redirects', + access: { read: () => true }, + fields: [ + { name: 'from', type: 'text', required: true, unique: true }, + { name: 'to', type: 'text', required: true }, + ], + ...options.overrides, + } + + return { + ...config, + collections: [...(config.collections || []), redirectsCollection], + } + } +``` + +## Adding Hooks + +```typescript +const resaveChildrenHook: CollectionAfterChangeHook = async ({ doc, req, operation }) => { + if (operation === 'update') { + const children = await req.payload.find({ + collection: 'pages', + where: { parent: { equals: doc.id } }, + }) + + for (const child of children.docs) { + await req.payload.update({ + collection: 'pages', + id: child.id, + data: child, + }) + } + } + return doc +} + +export const nestedDocsPlugin = + (options: { collections: string[] }): Plugin => + (config: Config): Config => ({ + ...config, + collections: (config.collections || []).map((collection) => { + if (options.collections.includes(collection.slug)) { + return { + ...collection, + hooks: { + ...(collection.hooks || {}), + afterChange: [resaveChildrenHook, ...(collection.hooks?.afterChange || [])], + }, + } + } + return collection + }), + }) +``` + +## Adding Root-Level Endpoints + +```typescript +export const seoPlugin = + (options: { generateTitle?: (doc: any) => string }): Plugin => + (config: Config): Config => { + const generateTitleEndpoint: Endpoint = { + path: '/plugin-seo/generate-title', + method: 'post', + handler: async (req) => { + const data = await req.json?.() + const result = options.generateTitle ? options.generateTitle(data.doc) : '' + return Response.json({ result }) + }, + } + + return { + ...config, + endpoints: [...(config.endpoints ?? []), generateTitleEndpoint], + } + } +``` + +## Field Overrides with Defaults + +```typescript +type FieldsOverride = (args: { defaultFields: Field[] }) => Field[] + +interface PluginConfig { + collections?: string[] + fields?: FieldsOverride +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const defaultFields: Field[] = [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ] + + const fields = + options.fields && typeof options.fields === 'function' + ? options.fields({ defaultFields }) + : defaultFields + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...fields], + } + } + return collection + }), + } + } +``` + +## Disable Plugin Pattern + +```typescript +interface PluginConfig { + disabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + // Always add collections/fields for database schema consistency + if (!config.collections) { + config.collections = [] + } + + config.collections.push({ + slug: 'plugin-collection', + fields: [{ name: 'title', type: 'text' }], + }) + + // If disabled, return early but keep schema changes + if (options.disabled) { + return config + } + + // Add endpoints, hooks, components only when enabled + config.endpoints = [ + ...(config.endpoints ?? []), + { + path: '/my-endpoint', + method: 'get', + handler: async () => Response.json({ message: 'Hello' }), + }, + ] + + return config + } +``` + +## Admin Components + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + if (!config.admin) config.admin = {} + if (!config.admin.components) config.admin.components = {} + if (!config.admin.components.beforeDashboard) { + config.admin.components.beforeDashboard = [] + } + + // Add client component + config.admin.components.beforeDashboard.push('my-plugin-name/client#BeforeDashboardClient') + + // Add server component (RSC) + config.admin.components.beforeDashboard.push('my-plugin-name/rsc#BeforeDashboardServer') + + return config + } +``` + +## onInit Hook + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const incomingOnInit = config.onInit + + config.onInit = async (payload) => { + // IMPORTANT: Call existing onInit first + if (incomingOnInit) await incomingOnInit(payload) + + // Plugin initialization + payload.logger.info('Plugin initialized') + + // Example: Seed data + const { totalDocs } = await payload.count({ + collection: 'plugin-collection', + where: { id: { equals: 'seeded-by-plugin' } }, + }) + + if (totalDocs === 0) { + await payload.create({ + collection: 'plugin-collection', + data: { id: 'seeded-by-plugin' }, + }) + } + } + + return config + } +``` + +## Best Practices + +### Preserve Existing Config + +```typescript +// ✅ Good +collections: [...(config.collections || []), newCollection] + +// ❌ Bad +collections: [newCollection] +``` + +### Respect User Overrides + +```typescript +const collection: CollectionConfig = { + slug: 'redirects', + fields: defaultFields, + ...options.overrides, // User overrides last +} +``` + +### Hook Composition + +```typescript +hooks: { + ...collection.hooks, + afterChange: [ + myHook, + ...(collection.hooks?.afterChange || []), + ], +} +``` + +### Type Safety + +```typescript +import type { Config, Plugin, CollectionConfig, Field } from 'payload' +``` diff --git a/templates/with-vercel-postgres/.cursor/rules/queries.md b/templates/with-vercel-postgres/.cursor/rules/queries.md new file mode 100644 index 00000000000..4920ec85f09 --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/queries.md @@ -0,0 +1,223 @@ +--- +title: Queries +description: Local API, REST, and GraphQL query patterns +tags: [payload, queries, local-api, rest, graphql] +--- + +# Payload CMS Queries + +## Query Operators + +```typescript +// Equals +{ color: { equals: 'blue' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater/less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In/not in +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (point fields) +{ location: { near: [10, 20, 5000] } } // [lng, lat, maxDistance] +``` + +## AND/OR Logic + +```typescript +{ + or: [ + { color: { equals: 'mint' } }, + { + and: [ + { color: { equals: 'white' } }, + { featured: { equals: false } }, + ], + }, + ], +} +``` + +## Nested Properties + +```typescript +{ + 'author.role': { equals: 'editor' }, + 'meta.featured': { exists: true }, +} +``` + +## Local API + +```typescript +// Find documents +const posts = await payload.find({ + collection: 'posts', + where: { + status: { equals: 'published' }, + 'author.name': { contains: 'john' }, + }, + depth: 2, // Populate relationships + limit: 10, + page: 1, + sort: '-createdAt', + locale: 'en', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const post = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { + status: 'published', + }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) + +// Count +const count = await payload.count({ + collection: 'posts', + where: { + status: { equals: 'published' }, + }, +}) +``` + +## Access Control in Local API + +**CRITICAL**: Local API bypasses access control by default (`overrideAccess: true`). + +```typescript +// ❌ WRONG: User is passed but access control is bypassed +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + // Result: Operation runs with ADMIN privileges +}) + +// ✅ CORRECT: Respects user's access control permissions +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + overrideAccess: false, // Required to enforce access control +}) + +// Administrative operation (intentionally bypass access control) +const allPosts = await payload.find({ + collection: 'posts', + // No user parameter, overrideAccess defaults to true +}) +``` + +**When to use `overrideAccess: false`:** + +- Performing operations on behalf of a user +- Testing access control logic +- API routes that should respect user permissions + +## REST API + +```typescript +import { stringify } from 'qs-esm' + +const query = { + status: { equals: 'published' }, +} + +const queryString = stringify( + { + where: query, + depth: 2, + limit: 10, + }, + { addQueryPrefix: true }, +) + +const response = await fetch(`https://api.example.com/api/posts${queryString}`) +const data = await response.json() +``` + +### REST Endpoints + +``` +GET /api/{collection} - Find documents +GET /api/{collection}/{id} - Find by ID +POST /api/{collection} - Create +PATCH /api/{collection}/{id} - Update +DELETE /api/{collection}/{id} - Delete +GET /api/{collection}/count - Count documents + +GET /api/globals/{slug} - Get global +POST /api/globals/{slug} - Update global +``` + +## GraphQL + +```graphql +query { + Posts(where: { status: { equals: published } }, limit: 10, sort: "-createdAt") { + docs { + id + title + author { + name + } + } + totalDocs + hasNextPage + } +} + +mutation { + createPost(data: { title: "New Post", status: draft }) { + id + title + } +} +``` + +## Performance Best Practices + +- Set `maxDepth` on relationships to prevent over-fetching +- Use `select` to limit returned fields +- Index frequently queried fields +- Use `virtual` fields for computed data +- Cache expensive operations in hook `context` diff --git a/templates/with-vercel-postgres/.cursor/rules/security-critical.mdc b/templates/with-vercel-postgres/.cursor/rules/security-critical.mdc new file mode 100644 index 00000000000..adf5d9e225d --- /dev/null +++ b/templates/with-vercel-postgres/.cursor/rules/security-critical.mdc @@ -0,0 +1,122 @@ +--- +title: Critical Security Patterns +description: The three most important security patterns in Payload CMS +tags: [payload, security, critical, access-control, transactions, hooks] +priority: high +--- + +# CRITICAL SECURITY PATTERNS + +These are the three most critical security patterns that MUST be followed in every Payload CMS project. + +## 1. Local API Access Control (MOST IMPORTANT) + +**By default, Local API operations bypass ALL access control**, even when passing a user. + +```typescript +// ❌ SECURITY BUG: Passes user but ignores their permissions +await payload.find({ + collection: 'posts', + user: someUser, // Access control is BYPASSED! +}) + +// ✅ SECURE: Actually enforces the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED for access control +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**When to use each:** + +- `overrideAccess: true` (default) - Server-side operations you trust (cron jobs, system tasks) +- `overrideAccess: false` - When operating on behalf of a user (API routes, webhooks) + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +## 2. Transaction Safety in Hooks + +**Nested operations in hooks without `req` break transaction atomicity.** + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ] +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ] +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +## 3. Prevent Infinite Hook Loops + +**Hooks triggering operations that trigger the same hooks create infinite loops.** + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ] +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ] +} +``` + +**Rule**: Use `req.context` flags to prevent hook loops diff --git a/templates/with-vercel-postgres/AGENTS.md b/templates/with-vercel-postgres/AGENTS.md new file mode 100644 index 00000000000..633b29b1f61 --- /dev/null +++ b/templates/with-vercel-postgres/AGENTS.md @@ -0,0 +1,1141 @@ +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default +6. **Access Control**: Ensure roles exist when modifiyng collection or globals with access controls + +### Code Validation + +- To validate typescript correctness after modifying code run `tsc --noEmit` +- Generate import maps after creating or modifying components. + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Configuration + +### Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Collections + +### Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +### Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Fields + +### Common Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## CRITICAL SECURITY PATTERNS + +### 1. Local API Access Control (MOST IMPORTANT) + +```typescript +// ❌ SECURITY BUG: Access control bypassed +await payload.find({ + collection: 'posts', + user: someUser, // Ignored! Operation runs with ADMIN privileges +}) + +// ✅ SECURE: Enforces user permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +### 2. Transaction Safety in Hooks + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ], +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ], +} +``` + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +### 3. Prevent Infinite Hook Loops + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ], +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ], +} +``` + +## Access Control + +### Collection-Level Access + +```typescript +import type { Access } from 'payload' + +// Boolean return +const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Query constraint (row-level security) +const ownPostsOnly: Access = ({ req: { user } }) => { + if (!user) return false + if (user?.roles?.includes('admin')) return true + + return { + author: { equals: user.id }, + } +} + +// Async access check +const projectMemberAccess: Access = async ({ req, id }) => { + const { user, payload } = req + + if (!user) return false + if (user.roles?.includes('admin')) return true + + const project = await payload.findByID({ + collection: 'projects', + id: id as string, + depth: 0, + }) + + return project.members?.includes(user.id) +} +``` + +### Field-Level Access + +```typescript +// Field access ONLY returns boolean (no query constraints) +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +### Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Hooks + +### Common Hook Patterns + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Queries + +### Local API + +```typescript +// Find with complex query +const posts = await payload.find({ + collection: 'posts', + where: { + and: [{ status: { equals: 'published' } }, { 'author.name': { contains: 'john' } }], + }, + depth: 2, // Populate relationships + limit: 10, + sort: '-createdAt', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const newPost = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { status: 'published' }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) +``` + +### Query Operators + +```typescript +// Equals +{ status: { equals: 'published' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater than / less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In array +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (geospatial) +{ location: { near: [-122.4194, 37.7749, 10000] } } +``` + +### AND/OR Logic + +```typescript +{ + or: [ + { status: { equals: 'published' } }, + { author: { equals: user.id } }, + ], +} + +{ + and: [ + { status: { equals: 'published' } }, + { featured: { equals: true } }, + ], +} +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Components + +The Admin Panel can be extensively customized using React Components. Custom Components can be Server Components (default) or Client Components. + +### Defining Components + +Components are defined using **file paths** (not direct imports) in your config: + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + // Logo and branding + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + + // Navigation + Nav: '/components/CustomNav', + beforeNavLinks: ['/components/CustomNavItem'], + afterNavLinks: ['/components/NavFooter'], + + // Header + header: ['/components/AnnouncementBanner'], + actions: ['/components/ClearCache', '/components/Preview'], + + // Dashboard + beforeDashboard: ['/components/WelcomeMessage'], + afterDashboard: ['/components/Analytics'], + + // Auth + beforeLogin: ['/components/SSOButtons'], + logout: { Button: '/components/LogoutButton' }, + + // Settings + settingsMenu: ['/components/SettingsMenu'], + + // Views + views: { + dashboard: { Component: '/components/CustomDashboard' }, + }, + }, + }, +}) +``` + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Server vs Client Components + +**All components are Server Components by default** (can use Local API directly): + +```tsx +// Server Component (default) +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const posts = await payload.find({ collection: 'posts' }) + return
{posts.totalDocs} posts
+} + +export default MyServerComponent +``` + +**Client Components** need the `'use client'` directive: + +```tsx +'use client' +import { useState } from 'react' +import { useAuth } from '@payloadcms/ui' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + const { user } = useAuth() + + return ( + + ) +} +``` + +### Using Hooks (Client Components Only) + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Document info (id, collection, etc.) + useField, // Field value and setter + useForm, // Form state + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +### Collection/Global Components + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/SaveDraft', + PublishButton: '/components/Publish', + }, + + // List view + list: { + Header: '/components/ListHeader', + beforeList: ['/components/BulkActions'], + afterList: ['/components/ListFooter'], + }, + }, + }, +} +``` + +### Field Components + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + // Edit view field + Field: '/components/StatusField', + // List view cell + Cell: '/components/StatusCell', + // Field label + Label: '/components/StatusLabel', + // Field description + Description: '/components/StatusDescription', + // Error message + Error: '/components/StatusError', + }, + }, +} +``` + +**UI Field** (presentational only, no data): + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +### Performance Best Practices + +1. **Import correctly:** + + - Admin Panel: `import { Button } from '@payloadcms/ui'` + - Frontend: `import { Button } from '@payloadcms/ui/elements/Button'` + +2. **Optimize re-renders:** + + ```tsx + // ❌ BAD: Re-renders on every form change + const { fields } = useForm() + + // ✅ GOOD: Only re-renders when specific field changes + const value = useFormFields(([fields]) => fields[path]) + ``` + +3. **Prefer Server Components** - Only use Client Components when you need: + + - State (useState, useReducer) + - Effects (useEffect) + - Event handlers (onClick, onChange) + - Browser APIs (localStorage, window) + +4. **Minimize serialized props** - Server Components serialize props sent to client + +### Styling Components + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Content
+} +``` + +```scss +// Use Payload's CSS variables +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} + +// Import Payload's SCSS library +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +### Type Safety + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, + SelectFieldServerComponent, + // ... etc +} from 'payload' + +export const MyField: TextFieldClientComponent = (props) => { + // Fully typed props +} +``` + +### Import Map + +Payload auto-generates `app/(payload)/admin/importMap.js` to resolve component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Set custom location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Custom Endpoints + +```typescript +import type { Endpoint } from 'payload' +import { APIError } from 'payload' + +// Always check authentication +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} + +// Route parameters +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Drafts & Versions + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} + +// Create draft +await payload.create({ + collection: 'pages', + data: { title: 'Draft Page' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft if available +}) +``` + +## Field Type Guards + +```typescript +import { + fieldAffectsData, + fieldHasSubFields, + fieldIsArrayType, + fieldIsBlockType, + fieldSupportsMany, + fieldHasMaxDepth, +} from 'payload' + +function processField(field: Field) { + // Check if field stores data + if (fieldAffectsData(field)) { + console.log(field.name) // Safe to access + } + + // Check if field has nested fields + if (fieldHasSubFields(field)) { + field.fields.forEach(processField) // Safe to access + } + + // Check field type + if (fieldIsArrayType(field)) { + console.log(field.minRows, field.maxRows) + } + + // Check capabilities + if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') + } +} +``` + +## Plugins + +### Using Plugins + +```typescript +import { seoPlugin } from '@payloadcms/plugin-seo' +import { redirectsPlugin } from '@payloadcms/plugin-redirects' + +export default buildConfig({ + plugins: [ + seoPlugin({ + collections: ['posts', 'pages'], + }), + redirectsPlugin({ + collections: ['pages'], + }), + ], +}) +``` + +### Creating Plugins + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + collections?: string[] + enabled?: boolean +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...collection.fields, { name: 'pluginField', type: 'text' }], + } + } + return collection + }), + }) +``` + +## Best Practices + +### Security + +1. Always set `overrideAccess: false` when passing `user` to Local API +2. Field-level access only returns boolean (no query constraints) +3. Default to restrictive access, gradually add permissions +4. Never trust client-provided data +5. Use `saveToJWT: true` for roles to avoid database lookups + +### Performance + +1. Index frequently queried fields +2. Use `select` to limit returned fields +3. Set `maxDepth` on relationships to prevent over-fetching +4. Use query constraints over async operations in access control +5. Cache expensive operations in `req.context` + +### Data Integrity + +1. Always pass `req` to nested operations in hooks +2. Use context flags to prevent infinite hook loops +3. Enable transactions for MongoDB (requires replica set) and Postgres +4. Use `beforeValidate` for data formatting +5. Use `beforeChange` for business logic + +### Type Safety + +1. Run `generate:types` after schema changes +2. Import types from generated `payload-types.ts` +3. Type your user object: `import type { User } from '@/payload-types'` +4. Use `as const` for field options +5. Use field type guards for runtime type checking + +### Organization + +1. Keep collections in separate files +2. Extract access control to `access/` directory +3. Extract hooks to `hooks/` directory +4. Use reusable field factories for common patterns +5. Document complex access control with comments + +## Common Gotchas + +1. **Local API Default**: Access control bypassed unless `overrideAccess: false` +2. **Transaction Safety**: Missing `req` in nested operations breaks atomicity +3. **Hook Loops**: Operations in hooks can trigger the same hooks +4. **Field Access**: Cannot use query constraints, only boolean +5. **Relationship Depth**: Default depth is 2, set to 0 for IDs only +6. **Draft Status**: `_status` field auto-injected when drafts enabled +7. **Type Generation**: Types not updated until `generate:types` runs +8. **MongoDB Transactions**: Require replica set configuration +9. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +10. **Point Fields**: Not supported in SQLite + +## Additional Context Files + +For deeper exploration of specific topics, refer to the context files located in `.cursor/rules/`: + +### Available Context Files + +1. **`payload-overview.md`** - High-level architecture and core concepts + + - Payload structure and initialization + - Configuration fundamentals + - Database adapters overview + +2. **`security-critical.md`** - Critical security patterns (⚠️ IMPORTANT) + + - Local API access control + - Transaction safety in hooks + - Preventing infinite hook loops + +3. **`collections.md`** - Collection configurations + + - Basic collection patterns + - Auth collections with RBAC + - Upload collections + - Drafts and versioning + - Globals + +4. **`fields.md`** - Field types and patterns + + - All field types with examples + - Conditional fields + - Virtual fields + - Field validation + - Common field patterns + +5. **`field-type-guards.md`** - TypeScript field type utilities + + - Field type checking utilities + - Safe type narrowing + - Runtime field validation + +6. **`access-control.md`** - Permission patterns + + - Collection-level access + - Field-level access + - Row-level security + - RBAC patterns + - Multi-tenant access control + +7. **`access-control-advanced.md`** - Complex access patterns + + - Nested document access + - Cross-collection permissions + - Dynamic role hierarchies + - Performance optimization + +8. **`hooks.md`** - Lifecycle hooks + + - Collection hooks + - Field hooks + - Hook context patterns + - Common hook recipes + +9. **`queries.md`** - Database operations + + - Local API usage + - Query operators + - Complex queries with AND/OR + - Performance optimization + +10. **`endpoints.md`** - Custom API endpoints + + - REST endpoint patterns + - Authentication in endpoints + - Error handling + - Route parameters + +11. **`adapters.md`** - Database and storage adapters + + - MongoDB, PostgreSQL, SQLite patterns + - Storage adapter usage (S3, Azure, GCS, etc.) + - Custom adapter development + +12. **`plugin-development.md`** - Creating plugins + + - Plugin architecture + - Modifying configuration + - Plugin hooks + - Best practices + +13. **`components.md`** - Custom Components + + - Component types (Root, Collection, Global, Field) + - Server vs Client Components + - Component paths and definition + - Default and custom props + - Using hooks + - Performance best practices + - Styling components + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/with-vercel-postgres/package.json b/templates/with-vercel-postgres/package.json index 12289222c2c..b9b3a92ed07 100644 --- a/templates/with-vercel-postgres/package.json +++ b/templates/with-vercel-postgres/package.json @@ -19,15 +19,15 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/db-vercel-postgres": "3.63.0", - "@payloadcms/next": "3.63.0", - "@payloadcms/richtext-lexical": "3.63.0", - "@payloadcms/storage-vercel-blob": "3.63.0", - "@payloadcms/ui": "3.63.0", + "@payloadcms/db-vercel-postgres": "3.68.5", + "@payloadcms/next": "3.68.5", + "@payloadcms/richtext-lexical": "3.68.5", + "@payloadcms/storage-vercel-blob": "3.68.5", + "@payloadcms/ui": "3.68.5", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.63.0", + "payload": "3.68.5", "react": "19.2.1", "react-dom": "19.2.1" }, @@ -49,7 +49,7 @@ "vite-tsconfig-paths": "5.1.4", "vitest": "3.2.3" }, - "packageManager": "pnpm@10.20.0", + "packageManager": "pnpm@10.26.0", "engines": { "node": "^18.20.2 || >=20.9.0" }, diff --git a/templates/with-vercel-postgres/src/migrations/20251107_183841_initial.json b/templates/with-vercel-postgres/src/migrations/20251216_194325_initial.json similarity index 99% rename from templates/with-vercel-postgres/src/migrations/20251107_183841_initial.json rename to templates/with-vercel-postgres/src/migrations/20251216_194325_initial.json index fc9ff555ed3..788eb1825b3 100644 --- a/templates/with-vercel-postgres/src/migrations/20251107_183841_initial.json +++ b/templates/with-vercel-postgres/src/migrations/20251216_194325_initial.json @@ -1,6 +1,4 @@ { - "id": "b1eec400-2402-4b9e-a2a6-1c3abe4d218f", - "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", "tables": { @@ -935,5 +933,7 @@ "schemas": {}, "tables": {}, "columns": {} - } + }, + "id": "633ac0dd-e243-41bc-8339-c40677f18590", + "prevId": "00000000-0000-0000-0000-000000000000" } diff --git a/templates/with-vercel-postgres/src/migrations/20251107_183841_initial.ts b/templates/with-vercel-postgres/src/migrations/20251216_194325_initial.ts similarity index 100% rename from templates/with-vercel-postgres/src/migrations/20251107_183841_initial.ts rename to templates/with-vercel-postgres/src/migrations/20251216_194325_initial.ts diff --git a/templates/with-vercel-postgres/src/migrations/index.ts b/templates/with-vercel-postgres/src/migrations/index.ts index e9a45811091..b4f4bbc2268 100644 --- a/templates/with-vercel-postgres/src/migrations/index.ts +++ b/templates/with-vercel-postgres/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20251107_183841_initial from './20251107_183841_initial' +import * as migration_20251216_194325_initial from './20251216_194325_initial' export const migrations = [ { - up: migration_20251107_183841_initial.up, - down: migration_20251107_183841_initial.down, - name: '20251107_183841_initial', + up: migration_20251216_194325_initial.up, + down: migration_20251216_194325_initial.down, + name: '20251216_194325_initial', }, ] diff --git a/templates/with-vercel-postgres/src/payload-types.ts b/templates/with-vercel-postgres/src/payload-types.ts index 0d481af819e..4133934a069 100644 --- a/templates/with-vercel-postgres/src/payload-types.ts +++ b/templates/with-vercel-postgres/src/payload-types.ts @@ -86,6 +86,7 @@ export interface Config { db: { defaultIDType: number; }; + fallbackLocale: null; globals: {}; globalsSelect: {}; locale: null; diff --git a/templates/with-vercel-postgres/src/payload.config.ts b/templates/with-vercel-postgres/src/payload.config.ts index d0b8c7b23e8..848fd31a40b 100644 --- a/templates/with-vercel-postgres/src/payload.config.ts +++ b/templates/with-vercel-postgres/src/payload.config.ts @@ -1,12 +1,11 @@ -import { vercelBlobStorage } from '@payloadcms/storage-vercel-blob' import { vercelPostgresAdapter } from '@payloadcms/db-vercel-postgres' import { lexicalEditor } from '@payloadcms/richtext-lexical' import path from 'path' import { buildConfig } from 'payload' import { fileURLToPath } from 'url' - import { Users } from './collections/Users' import { Media } from './collections/Media' +import { vercelBlobStorage } from '@payloadcms/storage-vercel-blob' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) diff --git a/templates/with-vercel-website/.cursor/rules/access-control-advanced.md b/templates/with-vercel-website/.cursor/rules/access-control-advanced.md new file mode 100644 index 00000000000..68f52fd1287 --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/access-control-advanced.md @@ -0,0 +1,519 @@ +--- +title: Access Control - Advanced Patterns +description: Context-aware, time-based, subscription-based access, factory functions, templates +tags: [payload, access-control, security, advanced, performance] +priority: high +--- + +# Advanced Access Control Patterns + +Advanced access control patterns including context-aware access, time-based restrictions, factory functions, and production templates. + +## Context-Aware Access Patterns + +### Locale-Specific Access + +```typescript +import type { Access } from 'payload' + +export const localeSpecificAccess: Access = ({ req: { user, locale } }) => { + // Authenticated users can access all locales + if (user) return true + + // Public users can only access English content + if (locale === 'en') return true + + return false +} +``` + +### Device-Specific Access + +```typescript +export const mobileOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return /mobile|android|iphone/i.test(userAgent) +} + +export const desktopOnlyAccess: Access = ({ req: { headers } }) => { + const userAgent = headers?.get('user-agent') || '' + return !/mobile|android|iphone/i.test(userAgent) +} +``` + +### IP-Based Access + +```typescript +export const restrictedIpAccess = (allowedIps: string[]): Access => { + return ({ req: { headers } }) => { + const ip = headers?.get('x-forwarded-for') || headers?.get('x-real-ip') + return allowedIps.includes(ip || '') + } +} + +// Usage +const internalIps = ['192.168.1.0/24', '10.0.0.5'] + +export const InternalDocs: CollectionConfig = { + slug: 'internal-docs', + access: { + read: restrictedIpAccess(internalIps), + }, +} +``` + +## Time-Based Access Patterns + +### Today's Records Only + +```typescript +export const todayOnlyAccess: Access = ({ req: { user } }) => { + if (!user) return false + + const now = new Date() + const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + const endOfDay = new Date(startOfDay.getTime() + 24 * 60 * 60 * 1000) + + return { + createdAt: { + greater_than_equal: startOfDay.toISOString(), + less_than: endOfDay.toISOString(), + }, + } +} +``` + +### Recent Records (Last N Days) + +```typescript +export const recentRecordsAccess = (days: number): Access => { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - days) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} + +// Usage: Users see only last 30 days, admins see all +export const Logs: CollectionConfig = { + slug: 'logs', + access: { + read: recentRecordsAccess(30), + }, +} +``` + +### Scheduled Content (Publish Date Range) + +```typescript +export const scheduledContentAccess: Access = ({ req: { user } }) => { + // Editors see all content + if (user?.roles?.includes('admin') || user?.roles?.includes('editor')) { + return true + } + + const now = new Date().toISOString() + + // Public sees only content within publish window + return { + and: [ + { publishDate: { less_than_equal: now } }, + { + or: [{ unpublishDate: { exists: false } }, { unpublishDate: { greater_than: now } }], + }, + ], + } +} +``` + +## Subscription-Based Access + +### Active Subscription Required + +```typescript +export const activeSubscriptionAccess: Access = async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + return subscription?.status === 'active' + } catch { + return false + } +} +``` + +### Subscription Tier-Based Access + +```typescript +export const tierBasedAccess = (requiredTier: string): Access => { + const tierHierarchy = ['free', 'basic', 'pro', 'enterprise'] + + return async ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + try { + const subscription = await req.payload.findByID({ + collection: 'subscriptions', + id: user.subscriptionId, + }) + + if (subscription?.status !== 'active') return false + + const userTierIndex = tierHierarchy.indexOf(subscription.tier) + const requiredTierIndex = tierHierarchy.indexOf(requiredTier) + + return userTierIndex >= requiredTierIndex + } catch { + return false + } + } +} + +// Usage +export const EnterpriseFeatures: CollectionConfig = { + slug: 'enterprise-features', + access: { + read: tierBasedAccess('enterprise'), + }, +} +``` + +## Factory Functions + +### createRoleBasedAccess + +```typescript +export function createRoleBasedAccess(roles: string[]): Access { + return ({ req: { user } }) => { + if (!user) return false + return roles.some((role) => user.roles?.includes(role)) + } +} + +// Usage +const adminOrEditor = createRoleBasedAccess(['admin', 'editor']) +const moderatorAccess = createRoleBasedAccess(['admin', 'moderator']) +``` + +### createOrgScopedAccess + +```typescript +export function createOrgScopedAccess(allowAdmin = true): Access { + return ({ req: { user } }) => { + if (!user) return false + if (allowAdmin && user.roles?.includes('admin')) return true + + return { + organizationId: { in: user.organizationIds || [] }, + } + } +} + +// Usage +const orgScoped = createOrgScopedAccess() // Admins bypass +const strictOrgScoped = createOrgScopedAccess(false) // Admins also scoped +``` + +### createTeamBasedAccess + +```typescript +export function createTeamBasedAccess(teamField = 'teamId'): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + [teamField]: { in: user.teamIds || [] }, + } + } +} +``` + +### createTimeLimitedAccess + +```typescript +export function createTimeLimitedAccess(daysAccess: number): Access { + return ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + const cutoff = new Date() + cutoff.setDate(cutoff.getDate() - daysAccess) + + return { + createdAt: { + greater_than_equal: cutoff.toISOString(), + }, + } + } +} +``` + +## Configuration Templates + +### Public + Authenticated Collection + +```typescript +export const PublicAuthCollection: CollectionConfig = { + slug: 'posts', + access: { + // Only admins/editors can create + create: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Authenticated users see all, public sees only published + read: ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } + }, + + // Only admins/editors can update + update: ({ req: { user } }) => { + return user?.roles?.some((role) => ['admin', 'editor'].includes(role)) || false + }, + + // Only admins can delete + delete: ({ req: { user } }) => { + return user?.roles?.includes('admin') || false + }, + }, + versions: { + drafts: true, + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'content', type: 'richText', required: true }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], +} +``` + +### Self-Service Collection + +```typescript +export const SelfServiceCollection: CollectionConfig = { + slug: 'users', + auth: true, + access: { + // Admins can create users + create: ({ req: { user } }) => user?.roles?.includes('admin') || false, + + // Anyone can read user profiles + read: () => true, + + // Users can update self, admins can update anyone + update: ({ req: { user }, id }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + return user.id === id + }, + + // Only admins can delete + delete: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + fields: [ + { name: 'name', type: 'text', required: true }, + { name: 'email', type: 'email', required: true }, + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + access: { + // Only admins can read/update roles + read: ({ req: { user } }) => user?.roles?.includes('admin') || false, + update: ({ req: { user } }) => user?.roles?.includes('admin') || false, + }, + }, + ], +} +``` + +## Performance Considerations + +### Avoid Async Operations in Hot Paths + +```typescript +// ❌ Slow: Multiple sequential async calls +export const slowAccess: Access = async ({ req: { user } }) => { + const org = await req.payload.findByID({ collection: 'orgs', id: user.orgId }) + const team = await req.payload.findByID({ collection: 'teams', id: user.teamId }) + const subscription = await req.payload.findByID({ collection: 'subs', id: user.subId }) + + return org.active && team.active && subscription.active +} + +// ✅ Fast: Use query constraints or cache in context +export const fastAccess: Access = ({ req: { user, context } }) => { + // Cache expensive lookups + if (!context.orgStatus) { + context.orgStatus = checkOrgStatus(user.orgId) + } + + return context.orgStatus +} +``` + +### Query Constraint Optimization + +```typescript +// ❌ Avoid: Non-indexed fields in constraints +export const slowQuery: Access = () => ({ + 'metadata.internalCode': { equals: 'ABC123' }, // Slow if not indexed +}) + +// ✅ Better: Use indexed fields +export const fastQuery: Access = () => ({ + status: { equals: 'active' }, // Indexed field + organizationId: { in: ['org1', 'org2'] }, // Indexed field +}) +``` + +### Field Access on Large Arrays + +```typescript +// ❌ Slow: Complex access on array fields +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: async ({ req }) => { + // Async call runs for EVERY array item + const result = await expensiveCheck() + return result + }, + }, + }, + ], +} + +// ✅ Fast: Simple checks or cache result +{ + name: 'items', + type: 'array', + fields: [ + { + name: 'secretData', + type: 'text', + access: { + read: ({ req: { user }, context }) => { + // Cache once, reuse for all items + if (context.canReadSecret === undefined) { + context.canReadSecret = user?.roles?.includes('admin') + } + return context.canReadSecret + }, + }, + }, + ], +} +``` + +### Avoid N+1 Queries + +```typescript +// ❌ N+1 Problem: Query per access check +export const n1Access: Access = async ({ req, id }) => { + // Runs for EACH document in list + const doc = await req.payload.findByID({ collection: 'docs', id }) + return doc.isPublic +} + +// ✅ Better: Use query constraint to filter at DB level +export const efficientAccess: Access = () => { + return { isPublic: { equals: true } } +} +``` + +## Debugging Tips + +### Log Access Check Execution + +```typescript +export const debugAccess: Access = ({ req: { user }, id }) => { + console.log('Access check:', { + userId: user?.id, + userRoles: user?.roles, + docId: id, + timestamp: new Date().toISOString(), + }) + return true +} +``` + +### Verify Arguments Availability + +```typescript +export const checkArgsAccess: Access = (args) => { + console.log('Available arguments:', { + hasReq: 'req' in args, + hasUser: args.req?.user ? 'yes' : 'no', + hasId: args.id ? 'provided' : 'undefined', + hasData: args.data ? 'provided' : 'undefined', + }) + return true +} +``` + +### Test Access Without User + +```typescript +// In test/development +const testAccess = await payload.find({ + collection: 'posts', + overrideAccess: false, // Enforce access control + user: undefined, // Simulate no user +}) + +console.log('Public access result:', testAccess.docs.length) +``` + +## Best Practices + +1. **Default Deny**: Start with restrictive access, gradually add permissions +2. **Type Guards**: Use TypeScript for user type safety +3. **Validate Data**: Never trust frontend-provided IDs or data +4. **Async for Critical Checks**: Use async operations for important security decisions +5. **Consistent Logic**: Apply same rules at field and collection levels +6. **Test Edge Cases**: Test with no user, wrong user, admin user scenarios +7. **Monitor Access**: Log failed access attempts for security review +8. **Regular Audit**: Review access rules quarterly or after major changes +9. **Cache Wisely**: Use `req.context` for expensive operations +10. **Document Intent**: Add comments explaining complex access rules +11. **Avoid Secrets in Client**: Never expose sensitive logic to client-side +12. **Handle Errors Gracefully**: Access functions should return `false` on error, not throw +13. **Test Local API**: Remember to set `overrideAccess: false` when testing +14. **Consider Performance**: Measure impact of async operations +15. **Principle of Least Privilege**: Grant minimum access required + +## Performance Summary + +**Minimize Async Operations**: Use query constraints over async lookups when possible + +**Cache Expensive Checks**: Store results in `req.context` for reuse + +**Index Query Fields**: Ensure fields in query constraints are indexed + +**Avoid Complex Logic in Array Fields**: Simple boolean checks preferred + +**Use Query Constraints**: Let database filter rather than loading all records diff --git a/templates/with-vercel-website/.cursor/rules/access-control.md b/templates/with-vercel-website/.cursor/rules/access-control.md new file mode 100644 index 00000000000..7b9a0a4ba5c --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/access-control.md @@ -0,0 +1,225 @@ +--- +title: Access Control +description: Collection, field, and global access control patterns +tags: [payload, access-control, security, permissions, rbac] +--- + +# Payload CMS Access Control + +## Access Control Layers + +1. **Collection-Level**: Controls operations on entire documents (create, read, update, delete, admin) +2. **Field-Level**: Controls access to individual fields (create, read, update) +3. **Global-Level**: Controls access to global documents (read, update) + +## Collection Access Control + +```typescript +import type { Access } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + // Boolean: Only authenticated users can create + create: ({ req: { user } }) => Boolean(user), + + // Query constraint: Public sees published, users see all + read: ({ req: { user } }) => { + if (user) return true + return { status: { equals: 'published' } } + }, + + // User-specific: Admins or document owner + update: ({ req: { user }, id }) => { + if (user?.roles?.includes('admin')) return true + return { author: { equals: user?.id } } + }, + + // Async: Check related data + delete: async ({ req, id }) => { + const hasComments = await req.payload.count({ + collection: 'comments', + where: { post: { equals: id } }, + }) + return hasComments === 0 + }, + }, +} +``` + +## Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Row-Level Security + +```typescript +// Organization-scoped access +export const organizationScoped: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + + // Users see only their organization's data + return { + organization: { + equals: user?.organization, + }, + } +} + +// Team-based access +export const teamMemberAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('admin')) return true + + return { + 'team.members': { + contains: user.id, + }, + } +} +``` + +## Field Access Control + +**Field access ONLY returns boolean** (no query constraints). + +```typescript +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +## RBAC Pattern + +Payload does NOT provide a roles system by default. Add a `roles` field to your auth collection: + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Multi-Tenant Access Control + +```typescript +interface User { + id: string + tenantId: string + roles?: string[] +} + +const tenantAccess: Access = ({ req: { user } }) => { + if (!user) return false + if (user.roles?.includes('super-admin')) return true + + return { + tenant: { + equals: (user as User).tenantId, + }, + } +} + +export const Posts: CollectionConfig = { + slug: 'posts', + access: { + create: tenantAccess, + read: tenantAccess, + update: tenantAccess, + delete: tenantAccess, + }, + fields: [ + { + name: 'tenant', + type: 'text', + required: true, + access: { + update: ({ req: { user } }) => user?.roles?.includes('super-admin'), + }, + hooks: { + beforeChange: [ + ({ req, operation, value }) => { + if (operation === 'create' && !value) { + return (req.user as User)?.tenantId + } + return value + }, + ], + }, + }, + ], +} +``` + +## Important Notes + +1. **Local API Default**: Access control is **skipped by default** in Local API (`overrideAccess: true`). When passing a `user` parameter, you must set `overrideAccess: false`: + +```typescript +// ❌ WRONG: Passes user but bypasses access control +await payload.find({ + collection: 'posts', + user: someUser, +}) + +// ✅ CORRECT: Respects the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // Required to enforce access control +}) +``` + +2. **Field Access Limitations**: Field-level access does NOT support query constraints - only boolean returns. + +3. **Admin Panel Visibility**: The `admin` access control determines if a collection appears in the admin panel for a user. diff --git a/templates/with-vercel-website/.cursor/rules/adapters.md b/templates/with-vercel-website/.cursor/rules/adapters.md new file mode 100644 index 00000000000..49b8b3367fc --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/adapters.md @@ -0,0 +1,209 @@ +--- +title: Database Adapters & Transactions +description: Database adapters, storage, email, and transaction patterns +tags: [payload, database, mongodb, postgres, sqlite, transactions] +--- + +# Payload CMS Adapters + +## Database Adapters + +### MongoDB + +```typescript +import { mongooseAdapter } from '@payloadcms/db-mongodb' + +export default buildConfig({ + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +### Postgres + +```typescript +import { postgresAdapter } from '@payloadcms/db-postgres' + +export default buildConfig({ + db: postgresAdapter({ + pool: { + connectionString: process.env.DATABASE_URI, + }, + push: false, // Don't auto-push schema changes + migrationDir: './migrations', + }), +}) +``` + +### SQLite + +```typescript +import { sqliteAdapter } from '@payloadcms/db-sqlite' + +export default buildConfig({ + db: sqliteAdapter({ + client: { + url: 'file:./payload.db', + }, + transactionOptions: {}, // Enable transactions (disabled by default) + }), +}) +``` + +## Transactions + +Payload automatically uses transactions for all-or-nothing database operations. + +### Threading req Through Operations + +**CRITICAL**: When performing nested operations in hooks, always pass `req` to maintain transaction context. + +```typescript +// ✅ CORRECT: Thread req through nested operations +const resaveChildren: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + // Find children - pass req + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + req, // Maintains transaction context + }) + + // Update each child - pass req + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + req, // Same transaction as parent operation + }) + } +} + +// ❌ WRONG: Missing req breaks transaction +const brokenHook: CollectionAfterChangeHook = async ({ collection, doc, req }) => { + const children = await req.payload.find({ + collection: 'children', + where: { parent: { equals: doc.id } }, + // Missing req - separate transaction or no transaction + }) + + for (const child of children.docs) { + await req.payload.update({ + id: child.id, + collection: 'children', + data: { updatedField: 'value' }, + // Missing req - if parent operation fails, these updates persist + }) + } +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +### Manual Transaction Control + +```typescript +const transactionID = await payload.db.beginTransaction() +try { + await payload.create({ + collection: 'orders', + data: orderData, + req: { transactionID }, + }) + await payload.update({ + collection: 'inventory', + id: itemId, + data: { stock: newStock }, + req: { transactionID }, + }) + await payload.db.commitTransaction(transactionID) +} catch (error) { + await payload.db.rollbackTransaction(transactionID) + throw error +} +``` + +## Storage Adapters + +Available storage adapters: + +- **@payloadcms/storage-s3** - AWS S3 +- **@payloadcms/storage-azure** - Azure Blob Storage +- **@payloadcms/storage-gcs** - Google Cloud Storage +- **@payloadcms/storage-r2** - Cloudflare R2 +- **@payloadcms/storage-vercel-blob** - Vercel Blob +- **@payloadcms/storage-uploadthing** - Uploadthing + +### AWS S3 + +```typescript +import { s3Storage } from '@payloadcms/storage-s3' + +export default buildConfig({ + plugins: [ + s3Storage({ + collections: { + media: true, + }, + bucket: process.env.S3_BUCKET, + config: { + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + region: process.env.S3_REGION, + }, + }), + ], +}) +``` + +## Email Adapters + +### Nodemailer (SMTP) + +```typescript +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' + +export default buildConfig({ + email: nodemailerAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + transportOptions: { + host: process.env.SMTP_HOST, + port: 587, + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }, + }), +}) +``` + +### Resend + +```typescript +import { resendAdapter } from '@payloadcms/email-resend' + +export default buildConfig({ + email: resendAdapter({ + defaultFromAddress: 'noreply@example.com', + defaultFromName: 'My App', + apiKey: process.env.RESEND_API_KEY, + }), +}) +``` + +## Important Notes + +1. **MongoDB Transactions**: Require replica set configuration +2. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +3. **Pass req**: Always pass `req` to nested operations in hooks for transaction safety +4. **Point Fields**: Not supported in SQLite diff --git a/templates/with-vercel-website/.cursor/rules/collections.md b/templates/with-vercel-website/.cursor/rules/collections.md new file mode 100644 index 00000000000..af625108e60 --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/collections.md @@ -0,0 +1,171 @@ +--- +title: Collections +description: Collection configurations and patterns +tags: [payload, collections, auth, upload, drafts] +--- + +# Payload CMS Collections + +## Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +## Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Upload Collection + +```typescript +export const Media: CollectionConfig = { + slug: 'media', + upload: { + staticDir: 'media', + mimeTypes: ['image/*'], + imageSizes: [ + { + name: 'thumbnail', + width: 400, + height: 300, + position: 'centre', + }, + { + name: 'card', + width: 768, + height: 1024, + }, + ], + adminThumbnail: 'thumbnail', + focalPoint: true, + crop: true, + }, + access: { + read: () => true, + }, + fields: [ + { + name: 'alt', + type: 'text', + required: true, + }, + ], +} +``` + +## Versioning & Drafts + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} +``` + +### Draft API Usage + +```typescript +// Create draft +await payload.create({ + collection: 'posts', + data: { title: 'Draft Post' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft version if exists +}) +``` + +## Globals + +Globals are single-instance documents (not collections). + +```typescript +import type { GlobalConfig } from 'payload' + +export const Header: GlobalConfig = { + slug: 'header', + label: 'Header', + admin: { + group: 'Settings', + }, + fields: [ + { + name: 'logo', + type: 'upload', + relationTo: 'media', + required: true, + }, + { + name: 'nav', + type: 'array', + maxRows: 8, + fields: [ + { + name: 'link', + type: 'relationship', + relationTo: 'pages', + }, + { + name: 'label', + type: 'text', + }, + ], + }, + ], +} +``` diff --git a/templates/with-vercel-website/.cursor/rules/components.md b/templates/with-vercel-website/.cursor/rules/components.md new file mode 100644 index 00000000000..8610b8d7b33 --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/components.md @@ -0,0 +1,794 @@ +# Custom Components in Payload CMS + +Custom Components allow you to fully customize the Admin Panel by swapping in your own React components. You can replace nearly every part of the interface or add entirely new functionality. + +## Component Types + +There are four main types of Custom Components: + +1. **Root Components** - Affect the Admin Panel globally (logo, nav, header) +2. **Collection Components** - Specific to collection views +3. **Global Components** - Specific to global document views +4. **Field Components** - Custom field UI and cells + +## Defining Custom Components + +### Component Paths + +Components are defined using file paths (not direct imports) to keep the config lightweight and Node.js compatible. + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + logout: { + Button: '/src/components/Logout#MyComponent', // Named export + }, + Nav: '/src/components/Nav', // Default export + }, + }, +}) +``` + +**Component Path Rules:** + +1. Paths are relative to project root (or `config.admin.importMap.baseDir`) +2. For **named exports**: append `#ExportName` or use `exportName` property +3. For **default exports**: no suffix needed +4. File extensions can be omitted + +### Component Config Object + +Instead of a string path, you can pass a config object: + +```typescript +{ + logout: { + Button: { + path: '/src/components/Logout', + exportName: 'MyComponent', + clientProps: { customProp: 'value' }, + serverProps: { asyncData: someData }, + }, + }, +} +``` + +**Config Properties:** + +| Property | Description | +| ------------- | ----------------------------------------------------- | +| `path` | File path to component (named exports via `#`) | +| `exportName` | Named export (alternative to `#` in path) | +| `clientProps` | Props for Client Components (must be serializable) | +| `serverProps` | Props for Server Components (can be non-serializable) | + +### Setting Base Directory + +```typescript +import path from 'path' +import { fileURLToPath } from 'node:url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), // Set base directory + }, + components: { + Nav: '/components/Nav', // Now relative to src/ + }, + }, +}) +``` + +## Server vs Client Components + +**All components are React Server Components by default.** + +### Server Components (Default) + +Can use Local API directly, perform async operations, and access full Payload instance. + +```tsx +import React from 'react' +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const page = await payload.findByID({ + collection: 'pages', + id: '123', + }) + + return

{page.title}

+} + +export default MyServerComponent +``` + +### Client Components + +Use the `'use client'` directive for interactivity, hooks, state, etc. + +```tsx +'use client' +import React, { useState } from 'react' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + + return +} +``` + +**Important:** Client Components cannot receive non-serializable props (functions, class instances, etc.). Payload automatically strips these when passing to client components. + +## Default Props + +All Custom Components receive these props by default: + +| Prop | Description | Type | +| --------- | ---------------------------------------- | --------- | +| `payload` | Payload instance (Local API access) | `Payload` | +| `i18n` | Internationalization object | `I18n` | +| `locale` | Current locale (if localization enabled) | `string` | + +**Server Component Example:** + +```tsx +async function MyComponent({ payload, i18n, locale }) { + const data = await payload.find({ + collection: 'posts', + locale, + }) + + return
{data.docs.length} posts
+} +``` + +**Client Component Example:** + +```tsx +'use client' +import { usePayload, useLocale, useTranslation } from '@payloadcms/ui' + +export function MyComponent() { + // Access via hooks in client components + const { getLocal, getByID } = usePayload() + const locale = useLocale() + const { t, i18n } = useTranslation() + + return
{t('myKey')}
+} +``` + +## Custom Props + +Pass additional props using `clientProps` or `serverProps`: + +```typescript +{ + logout: { + Button: { + path: '/components/Logout', + clientProps: { + buttonText: 'Sign Out', + onLogout: () => console.log('Logged out'), + }, + }, + }, +} +``` + +Receive in component: + +```tsx +'use client' +export function Logout({ buttonText, onLogout }) { + return +} +``` + +## Root Components + +Root Components affect the entire Admin Panel. + +### Available Root Components + +| Component | Description | Config Path | +| ----------------- | -------------------------------- | ---------------------------------- | +| `Nav` | Entire navigation sidebar | `admin.components.Nav` | +| `graphics.Icon` | Small icon (used in nav) | `admin.components.graphics.Icon` | +| `graphics.Logo` | Full logo (used on login) | `admin.components.graphics.Logo` | +| `logout.Button` | Logout button | `admin.components.logout.Button` | +| `actions` | Header actions (array) | `admin.components.actions` | +| `header` | Above header (array) | `admin.components.header` | +| `beforeDashboard` | Before dashboard content (array) | `admin.components.beforeDashboard` | +| `afterDashboard` | After dashboard content (array) | `admin.components.afterDashboard` | +| `beforeLogin` | Before login form (array) | `admin.components.beforeLogin` | +| `afterLogin` | After login form (array) | `admin.components.afterLogin` | +| `beforeNavLinks` | Before nav links (array) | `admin.components.beforeNavLinks` | +| `afterNavLinks` | After nav links (array) | `admin.components.afterNavLinks` | +| `settingsMenu` | Settings menu items (array) | `admin.components.settingsMenu` | +| `providers` | Custom React Context providers | `admin.components.providers` | +| `views` | Custom views (dashboard, etc.) | `admin.components.views` | + +### Example: Custom Logo + +```typescript +export default buildConfig({ + admin: { + components: { + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + }, + }, +}) +``` + +```tsx +// components/Logo.tsx +export default function Logo() { + return My Brand +} +``` + +### Example: Header Actions + +```typescript +export default buildConfig({ + admin: { + components: { + actions: ['/components/ClearCacheButton', '/components/PreviewButton'], + }, + }, +}) +``` + +```tsx +// components/ClearCacheButton.tsx +'use client' +export default function ClearCacheButton() { + return ( + + ) +} +``` + +## Collection Components + +Collection Components are specific to a collection's views. + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view components + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/CustomSaveDraft', + PublishButton: '/components/CustomPublish', + }, + + // List view components + list: { + Header: '/components/PostsListHeader', + beforeList: ['/components/ListFilters'], + afterList: ['/components/ListFooter'], + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Global Components + +Similar to Collection Components but for Global documents. + +```typescript +import type { GlobalConfig } from 'payload' + +export const Settings: GlobalConfig = { + slug: 'settings', + admin: { + components: { + edit: { + PreviewButton: '/components/SettingsPreview', + SaveButton: '/components/SettingsSave', + }, + }, + }, + fields: [ + // ... + ], +} +``` + +## Field Components + +Customize how fields render in Edit and List views. + +### Field Component (Edit View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Field: '/components/StatusField', + }, + }, +} +``` + +```tsx +// components/StatusField.tsx +'use client' +import { useField } from '@payloadcms/ui' +import type { SelectFieldClientComponent } from 'payload' + +export const StatusField: SelectFieldClientComponent = ({ path, field }) => { + const { value, setValue } = useField({ path }) + + return ( +
+ + +
+ ) +} +``` + +### Cell Component (List View) + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + Cell: '/components/StatusCell', + }, + }, +} +``` + +```tsx +// components/StatusCell.tsx +import type { SelectFieldCellComponent } from 'payload' + +export const StatusCell: SelectFieldCellComponent = ({ data, cellData }) => { + const isPublished = cellData === 'published' + + return ( + + {cellData} + + ) +} +``` + +### UI Field (Presentational Only) + +Special field type for adding custom UI without affecting data: + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +```tsx +// components/RefundButton.tsx +'use client' +import { useDocumentInfo } from '@payloadcms/ui' + +export default function RefundButton() { + const { id } = useDocumentInfo() + + return ( + + ) +} +``` + +## Using Hooks + +Payload provides many React hooks for Client Components: + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Current document info (id, slug, etc.) + useField, // Field value and setValue + useForm, // Form state and dispatch + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +**Important:** These hooks only work in Client Components within the Admin Panel context. + +## Accessing Payload Config + +**In Server Components:** + +```tsx +async function MyServerComponent({ payload }) { + const { config } = payload + return
{config.serverURL}
+} +``` + +**In Client Components:** + +```tsx +'use client' +import { useConfig } from '@payloadcms/ui' + +export function MyClientComponent() { + const { config } = useConfig() // Client-safe config + return
{config.serverURL}
+} +``` + +**Important:** Client Components receive a serializable version of the config (functions, validation, etc. are stripped). + +## Field Config Access + +**Server Component:** + +```tsx +import type { TextFieldServerComponent } from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = ({ field }) => { + return
Field name: {field.name}
+} +``` + +**Client Component:** + +```tsx +'use client' +import type { TextFieldClientComponent } from 'payload' + +export const MyFieldComponent: TextFieldClientComponent = ({ clientField }) => { + // clientField has non-serializable props removed + return
Field name: {clientField.name}
+} +``` + +## Translations (i18n) + +**Server Component:** + +```tsx +import { getTranslation } from '@payloadcms/translations' + +async function MyServerComponent({ i18n }) { + const translatedTitle = getTranslation(myTranslation, i18n) + return

{translatedTitle}

+} +``` + +**Client Component:** + +```tsx +'use client' +import { useTranslation } from '@payloadcms/ui' + +export function MyClientComponent() { + const { t, i18n } = useTranslation() + + return ( +
+

{t('namespace:key', { variable: 'value' })}

+

Language: {i18n.language}

+
+ ) +} +``` + +## Styling Components + +### Using CSS Variables + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Custom Component
+} +``` + +```scss +// styles.scss +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} +``` + +### Importing Payload SCSS + +```scss +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +## Common Patterns + +### Conditional Field Visibility + +```tsx +'use client' +import { useFormFields } from '@payloadcms/ui' +import type { TextFieldClientComponent } from 'payload' + +export const ConditionalField: TextFieldClientComponent = ({ path }) => { + const showField = useFormFields(([fields]) => fields.enableFeature?.value) + + if (!showField) return null + + return +} +``` + +### Loading Data from API + +```tsx +'use client' +import { useState, useEffect } from 'react' + +export function DataLoader() { + const [data, setData] = useState(null) + + useEffect(() => { + fetch('/api/custom-data') + .then((res) => res.json()) + .then(setData) + }, []) + + return
{JSON.stringify(data)}
+} +``` + +### Using Local API in Server Components + +```tsx +import type { Payload } from 'payload' + +async function RelatedPosts({ payload, id }: { payload: Payload; id: string }) { + const post = await payload.findByID({ + collection: 'posts', + id, + depth: 0, + }) + + const related = await payload.find({ + collection: 'posts', + where: { + category: { equals: post.category }, + id: { not_equals: id }, + }, + limit: 5, + }) + + return ( +
+

Related Posts

+
    + {related.docs.map((doc) => ( +
  • {doc.title}
  • + ))} +
+
+ ) +} + +export default RelatedPosts +``` + +## Performance Best Practices + +### 1. Minimize Client Bundle Size + +```tsx +// ❌ BAD: Imports entire package +'use client' +import { Button } from '@payloadcms/ui' + +// ✅ GOOD: Tree-shakeable import for frontend +import { Button } from '@payloadcms/ui/elements/Button' +``` + +**Rule:** In Admin Panel UI, import from `@payloadcms/ui`. In frontend code, use specific paths. + +### 2. Optimize Re-renders + +```tsx +// ❌ BAD: Re-renders on every form change +'use client' +import { useForm } from '@payloadcms/ui' + +export function MyComponent() { + const { fields } = useForm() + // Re-renders on ANY field change +} + +// ✅ GOOD: Only re-renders when specific field changes +;('use client') +import { useFormFields } from '@payloadcms/ui' + +export function MyComponent({ path }) { + const value = useFormFields(([fields]) => fields[path]) + // Only re-renders when this field changes +} +``` + +### 3. Use Server Components When Possible + +```tsx +// ✅ GOOD: No JavaScript sent to client +async function PostCount({ payload }) { + const { totalDocs } = await payload.find({ + collection: 'posts', + limit: 0, + }) + + return

{totalDocs} posts

+} + +// Only use client components when you need: +// - State (useState, useReducer) +// - Effects (useEffect) +// - Event handlers (onClick, onChange) +// - Browser APIs (localStorage, window) +``` + +### 4. React Best Practices + +- Use React.memo() for expensive components +- Implement proper key props in lists +- Avoid inline function definitions in renders +- Use Suspense boundaries for async operations + +## Import Map + +Payload generates an import map at `app/(payload)/admin/importMap.js` that resolves all component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Override location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Type Safety + +Use Payload's TypeScript types for components: + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, +} from 'payload' + +export const MyFieldComponent: TextFieldServerComponent = (props) => { + // Fully typed props +} +``` + +## Troubleshooting + +### "useConfig is undefined" or similar hook errors + +**Cause:** Dependency version mismatch between Payload packages. + +**Solution:** Pin all `@payloadcms/*` packages to the exact same version: + +```json +{ + "dependencies": { + "payload": "3.0.0", + "@payloadcms/ui": "3.0.0", + "@payloadcms/richtext-lexical": "3.0.0" + } +} +``` + +### Component not loading + +1. Check file path is correct (relative to baseDir) +2. Verify named export syntax: `/path/to/file#ExportName` +3. Run `payload generate:importmap` to regenerate +4. Check for TypeScript errors in component file + +## Resources + +- [Custom Components Docs](https://payloadcms.com/docs/custom-components/overview) +- [Root Components](https://payloadcms.com/docs/custom-components/root-components) +- [Custom Views](https://payloadcms.com/docs/custom-components/custom-views) +- [React Hooks](https://payloadcms.com/docs/admin/react-hooks) +- [Custom CSS](https://payloadcms.com/docs/admin/customizing-css) diff --git a/templates/with-vercel-website/.cursor/rules/endpoints.md b/templates/with-vercel-website/.cursor/rules/endpoints.md new file mode 100644 index 00000000000..8a2481dbe5d --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/endpoints.md @@ -0,0 +1,236 @@ +--- +title: Custom Endpoints +description: Custom REST API endpoints with authentication and helpers +tags: [payload, endpoints, api, routes, webhooks] +--- + +# Payload Custom Endpoints + +## Basic Endpoint Pattern + +Custom endpoints are **not authenticated by default**. Always check `req.user`. + +```typescript +import { APIError } from 'payload' +import type { Endpoint } from 'payload' + +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} +``` + +## Route Parameters + +```typescript +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Request Body Handling + +```typescript +// Manual JSON parsing +export const createEndpoint: Endpoint = { + path: '/create', + method: 'post', + handler: async (req) => { + const data = await req.json() + + const result = await req.payload.create({ + collection: 'posts', + data, + }) + + return Response.json(result) + }, +} + +// Using helper (handles JSON + files) +import { addDataAndFileToRequest } from 'payload' + +export const uploadEndpoint: Endpoint = { + path: '/upload', + method: 'post', + handler: async (req) => { + await addDataAndFileToRequest(req) + + // req.data contains parsed body + // req.file contains uploaded file (if multipart) + + const result = await req.payload.create({ + collection: 'media', + data: req.data, + file: req.file, + }) + + return Response.json(result) + }, +} +``` + +## Query Parameters + +```typescript +export const searchEndpoint: Endpoint = { + path: '/search', + method: 'get', + handler: async (req) => { + const url = new URL(req.url) + const query = url.searchParams.get('q') + const limit = parseInt(url.searchParams.get('limit') || '10') + + const results = await req.payload.find({ + collection: 'posts', + where: { + title: { + contains: query, + }, + }, + limit, + }) + + return Response.json(results) + }, +} +``` + +## CORS Headers + +```typescript +import { headersWithCors } from 'payload' + +export const corsEndpoint: Endpoint = { + path: '/public-data', + method: 'get', + handler: async (req) => { + const data = await fetchPublicData() + + return Response.json(data, { + headers: headersWithCors({ + headers: new Headers(), + req, + }), + }) + }, +} +``` + +## Error Handling + +```typescript +import { APIError } from 'payload' + +export const validateEndpoint: Endpoint = { + path: '/validate', + method: 'post', + handler: async (req) => { + const data = await req.json() + + if (!data.email) { + throw new APIError('Email is required', 400) + } + + return Response.json({ valid: true }) + }, +} +``` + +## Endpoint Placement + +### Collection Endpoints + +Mounted at `/api/{collection-slug}/{path}`. + +```typescript +export const Orders: CollectionConfig = { + slug: 'orders', + endpoints: [ + { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + // Available at: /api/orders/:id/tracking + const orderId = req.routeParams.id + return Response.json({ orderId }) + }, + }, + ], +} +``` + +### Global Endpoints + +Mounted at `/api/globals/{global-slug}/{path}`. + +```typescript +export const Settings: GlobalConfig = { + slug: 'settings', + endpoints: [ + { + path: '/clear-cache', + method: 'post', + handler: async (req) => { + // Available at: /api/globals/settings/clear-cache + await clearCache() + return Response.json({ message: 'Cache cleared' }) + }, + }, + ], +} +``` + +### Root Endpoints + +Mounted at `/api/{path}`. + +```typescript +export default buildConfig({ + endpoints: [ + { + path: '/hello', + method: 'get', + handler: () => { + // Available at: /api/hello + return Response.json({ message: 'Hello!' }) + }, + }, + ], +}) +``` + +## Best Practices + +1. **Always check authentication** - Custom endpoints are not authenticated by default +2. **Use `req.payload` for operations** - Ensures access control and hooks execute +3. **Use helpers for common tasks** - `addDataAndFileToRequest`, `headersWithCors` +4. **Throw `APIError` for errors** - Provides consistent error responses +5. **Return Web API `Response`** - Use `Response.json()` for consistent responses +6. **Validate input** - Check required fields, validate types +7. **Log errors** - Use `req.payload.logger` for debugging diff --git a/templates/with-vercel-website/.cursor/rules/field-type-guards.md b/templates/with-vercel-website/.cursor/rules/field-type-guards.md new file mode 100644 index 00000000000..3514ad44993 --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/field-type-guards.md @@ -0,0 +1,230 @@ +--- +title: Field Type Guards +description: Runtime field type checking and safe type narrowing +tags: [payload, typescript, type-guards, fields] +--- + +# Payload Field Type Guards + +Type guards for runtime field type checking and safe type narrowing. + +## Most Common Guards + +### fieldAffectsData + +**Most commonly used guard.** Checks if field stores data (has name and is not UI-only). + +```typescript +import { fieldAffectsData } from 'payload' + +function generateSchema(fields: Field[]) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + // Safe to access field.name + schema[field.name] = getFieldType(field) + } + }) +} + +// Filter data fields +const dataFields = fields.filter(fieldAffectsData) +``` + +### fieldHasSubFields + +Checks if field contains nested fields (group, array, row, or collapsible). + +```typescript +import { fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[]): void { + fields.forEach((field) => { + if (fieldHasSubFields(field)) { + // Safe to access field.fields + traverseFields(field.fields) + } + }) +} +``` + +### fieldIsArrayType + +Checks if field type is `'array'`. + +```typescript +import { fieldIsArrayType } from 'payload' + +if (fieldIsArrayType(field)) { + // field.type === 'array' + console.log(`Min rows: ${field.minRows}`) + console.log(`Max rows: ${field.maxRows}`) +} +``` + +## Capability Guards + +### fieldSupportsMany + +Checks if field can have multiple values (select, relationship, or upload with `hasMany`). + +```typescript +import { fieldSupportsMany } from 'payload' + +if (fieldSupportsMany(field)) { + // field.type is 'select' | 'relationship' | 'upload' + if (field.hasMany) { + console.log('Field accepts multiple values') + } +} +``` + +### fieldHasMaxDepth + +Checks if field is relationship/upload/join with numeric `maxDepth` property. + +```typescript +import { fieldHasMaxDepth } from 'payload' + +if (fieldHasMaxDepth(field)) { + // field.type is 'upload' | 'relationship' | 'join' + // AND field.maxDepth is number + const remainingDepth = field.maxDepth - currentDepth +} +``` + +### fieldIsVirtual + +Checks if field is virtual (computed or virtual relationship). + +```typescript +import { fieldIsVirtual } from 'payload' + +if (fieldIsVirtual(field)) { + // field.virtual is truthy + if (typeof field.virtual === 'string') { + console.log(`Virtual path: ${field.virtual}`) + } +} +``` + +## Type Checking Guards + +### fieldIsBlockType + +```typescript +import { fieldIsBlockType } from 'payload' + +if (fieldIsBlockType(field)) { + // field.type === 'blocks' + field.blocks.forEach((block) => { + console.log(`Block: ${block.slug}`) + }) +} +``` + +### fieldIsGroupType + +```typescript +import { fieldIsGroupType } from 'payload' + +if (fieldIsGroupType(field)) { + // field.type === 'group' + console.log(`Interface: ${field.interfaceName}`) +} +``` + +### fieldIsPresentationalOnly + +```typescript +import { fieldIsPresentationalOnly } from 'payload' + +if (fieldIsPresentationalOnly(field)) { + // field.type === 'ui' + // Skip in data operations, GraphQL schema, etc. + return +} +``` + +## Common Patterns + +### Recursive Field Traversal + +```typescript +import { fieldAffectsData, fieldHasSubFields } from 'payload' + +function traverseFields(fields: Field[], callback: (field: Field) => void) { + fields.forEach((field) => { + if (fieldAffectsData(field)) { + callback(field) + } + + if (fieldHasSubFields(field)) { + traverseFields(field.fields, callback) + } + }) +} +``` + +### Filter Data-Bearing Fields + +```typescript +import { fieldAffectsData, fieldIsPresentationalOnly, fieldIsHiddenOrDisabled } from 'payload' + +const dataFields = fields.filter( + (field) => + fieldAffectsData(field) && !fieldIsPresentationalOnly(field) && !fieldIsHiddenOrDisabled(field), +) +``` + +### Container Type Switching + +```typescript +import { fieldIsArrayType, fieldIsBlockType, fieldHasSubFields } from 'payload' + +if (fieldIsArrayType(field)) { + // Handle array-specific logic +} else if (fieldIsBlockType(field)) { + // Handle blocks-specific logic +} else if (fieldHasSubFields(field)) { + // Handle group/row/collapsible +} +``` + +### Safe Property Access + +```typescript +import { fieldSupportsMany, fieldHasMaxDepth } from 'payload' + +// With guard - safe access +if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') +} + +if (fieldHasMaxDepth(field)) { + const depth = field.maxDepth // TypeScript knows this is number +} +``` + +## All Available Guards + +| Type Guard | Checks For | Use When | +| --------------------------- | --------------------------------- | ---------------------------------------- | +| `fieldAffectsData` | Field stores data (has name) | Need to access field data or name | +| `fieldHasSubFields` | Field contains nested fields | Recursively traverse fields | +| `fieldIsArrayType` | Field is array type | Distinguish arrays from other containers | +| `fieldIsBlockType` | Field is blocks type | Handle blocks-specific logic | +| `fieldIsGroupType` | Field is group type | Handle group-specific logic | +| `fieldSupportsMany` | Field can have multiple values | Check for `hasMany` support | +| `fieldHasMaxDepth` | Field supports depth control | Control relationship/upload/join depth | +| `fieldIsPresentationalOnly` | Field is UI-only | Exclude from data operations | +| `fieldIsSidebar` | Field positioned in sidebar | Separate sidebar rendering | +| `fieldIsID` | Field name is 'id' | Special ID field handling | +| `fieldIsHiddenOrDisabled` | Field is hidden or disabled | Filter from UI operations | +| `fieldShouldBeLocalized` | Field needs localization | Proper locale table checks | +| `fieldIsVirtual` | Field is virtual | Skip in database transforms | +| `tabHasName` | Tab is named (stores data) | Distinguish named vs unnamed tabs | +| `groupHasName` | Group is named (stores data) | Distinguish named vs unnamed groups | +| `optionIsObject` | Option is `{label, value}` | Access option properties safely | +| `optionsAreObjects` | All options are objects | Batch option processing | +| `optionIsValue` | Option is string value | Handle string options | +| `valueIsValueWithRelation` | Value is polymorphic relationship | Handle polymorphic relationships | diff --git a/templates/with-vercel-website/.cursor/rules/fields.md b/templates/with-vercel-website/.cursor/rules/fields.md new file mode 100644 index 00000000000..8468e41f599 --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/fields.md @@ -0,0 +1,317 @@ +--- +title: Fields +description: Field types, patterns, and configurations +tags: [payload, fields, validation, conditional] +--- + +# Payload CMS Fields + +## Common Field Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## Field Types + +### Text Field + +```typescript +{ + name: 'title', + type: 'text', + required: true, + unique: true, + minLength: 5, + maxLength: 100, + index: true, + localized: true, + defaultValue: 'Default Title', + validate: (value) => Boolean(value) || 'Required', + admin: { + placeholder: 'Enter title...', + position: 'sidebar', + condition: (data) => data.showTitle === true, + }, +} +``` + +### Rich Text (Lexical) + +```typescript +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import { HeadingFeature, LinkFeature } from '@payloadcms/richtext-lexical' + +{ + name: 'content', + type: 'richText', + required: true, + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + HeadingFeature({ + enabledHeadingSizes: ['h1', 'h2', 'h3'], + }), + LinkFeature({ + enabledCollections: ['posts', 'pages'], + }), + ], + }), +} +``` + +### Relationship + +```typescript +// Single relationship +{ + name: 'author', + type: 'relationship', + relationTo: 'users', + required: true, + maxDepth: 2, +} + +// Multiple relationships (hasMany) +{ + name: 'categories', + type: 'relationship', + relationTo: 'categories', + hasMany: true, + filterOptions: { + active: { equals: true }, + }, +} + +// Polymorphic relationship +{ + name: 'relatedContent', + type: 'relationship', + relationTo: ['posts', 'pages'], + hasMany: true, +} +``` + +### Array + +```typescript +{ + name: 'slides', + type: 'array', + minRows: 2, + maxRows: 10, + labels: { + singular: 'Slide', + plural: 'Slides', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'image', + type: 'upload', + relationTo: 'media', + }, + ], + admin: { + initCollapsed: true, + }, +} +``` + +### Blocks + +```typescript +import type { Block } from 'payload' + +const HeroBlock: Block = { + slug: 'hero', + interfaceName: 'HeroBlock', + fields: [ + { + name: 'heading', + type: 'text', + required: true, + }, + { + name: 'background', + type: 'upload', + relationTo: 'media', + }, + ], +} + +const ContentBlock: Block = { + slug: 'content', + fields: [ + { + name: 'text', + type: 'richText', + }, + ], +} + +{ + name: 'layout', + type: 'blocks', + blocks: [HeroBlock, ContentBlock], +} +``` + +### Select + +```typescript +{ + name: 'status', + type: 'select', + options: [ + { label: 'Draft', value: 'draft' }, + { label: 'Published', value: 'published' }, + ], + defaultValue: 'draft', + required: true, +} + +// Multiple select +{ + name: 'tags', + type: 'select', + hasMany: true, + options: ['tech', 'news', 'sports'], +} +``` + +### Upload + +```typescript +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + required: true, + filterOptions: { + mimeType: { contains: 'image' }, + }, +} +``` + +### Point (Geolocation) + +```typescript +{ + name: 'location', + type: 'point', + label: 'Location', + required: true, +} + +// Query by distance +const nearbyLocations = await payload.find({ + collection: 'stores', + where: { + location: { + near: [10, 20], // [longitude, latitude] + maxDistance: 5000, // in meters + minDistance: 1000, + }, + }, +}) +``` + +### Join Fields (Reverse Relationships) + +```typescript +// From Users collection - show user's orders +{ + name: 'orders', + type: 'join', + collection: 'orders', + on: 'customer', // The field in 'orders' that references this user +} +``` + +### Tabs & Groups + +```typescript +// Tabs +{ + type: 'tabs', + tabs: [ + { + label: 'Content', + fields: [ + { name: 'title', type: 'text' }, + { name: 'body', type: 'richText' }, + ], + }, + { + label: 'SEO', + fields: [ + { name: 'metaTitle', type: 'text' }, + { name: 'metaDescription', type: 'textarea' }, + ], + }, + ], +} + +// Group (named) +{ + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], +} +``` + +## Validation + +```typescript +{ + name: 'email', + type: 'email', + validate: (value, { operation, data, siblingData }) => { + if (operation === 'create' && !value) { + return 'Email is required' + } + if (value && !value.includes('@')) { + return 'Invalid email format' + } + return true + }, +} +``` diff --git a/templates/with-vercel-website/.cursor/rules/hooks.md b/templates/with-vercel-website/.cursor/rules/hooks.md new file mode 100644 index 00000000000..1f168f9eaeb --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/hooks.md @@ -0,0 +1,175 @@ +--- +title: Hooks +description: Collection hooks, field hooks, and context patterns +tags: [payload, hooks, lifecycle, context] +--- + +# Payload CMS Hooks + +## Collection Hooks + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Field Hooks + +```typescript +import type { FieldHook } from 'payload' + +const beforeValidateHook: FieldHook = ({ value }) => { + return value.trim().toLowerCase() +} + +const afterReadHook: FieldHook = ({ value, req }) => { + // Hide email from non-admins + if (!req.user?.roles?.includes('admin')) { + return value.replace(/(.{2})(.*)(@.*)/, '$1***$3') + } + return value +} + +{ + name: 'email', + type: 'email', + hooks: { + beforeValidate: [beforeValidateHook], + afterRead: [afterReadHook], + }, +} +``` + +## Hook Context + +Share data between hooks or control hook behavior using request context: + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + beforeChange: [ + async ({ context }) => { + context.expensiveData = await fetchExpensiveData() + }, + ], + afterChange: [ + async ({ context, doc }) => { + // Reuse from previous hook + await processData(doc, context.expensiveData) + }, + ], + }, +} +``` + +## Next.js Revalidation Pattern + +```typescript +import type { CollectionAfterChangeHook } from 'payload' +import { revalidatePath } from 'next/cache' + +export const revalidatePage: CollectionAfterChangeHook = ({ + doc, + previousDoc, + req: { payload, context }, +}) => { + if (!context.disableRevalidate) { + if (doc._status === 'published') { + const path = doc.slug === 'home' ? '/' : `/${doc.slug}` + payload.logger.info(`Revalidating page at path: ${path}`) + revalidatePath(path) + } + + // Revalidate old path if unpublished + if (previousDoc?._status === 'published' && doc._status !== 'published') { + const oldPath = previousDoc.slug === 'home' ? '/' : `/${previousDoc.slug}` + revalidatePath(oldPath) + } + } + return doc +} +``` + +## Date Field Auto-Set + +```typescript +{ + name: 'publishedOn', + type: 'date', + hooks: { + beforeChange: [ + ({ siblingData, value }) => { + if (siblingData._status === 'published' && !value) { + return new Date() + } + return value + }, + ], + }, +} +``` + +## Best Practices + +- Use `beforeValidate` for data formatting +- Use `beforeChange` for business logic +- Use `afterChange` for side effects +- Use `afterRead` for computed fields +- Store expensive operations in `context` +- Pass `req` to nested operations for transaction safety +- Use context flags to prevent infinite loops diff --git a/templates/with-vercel-website/.cursor/rules/payload-overview.md b/templates/with-vercel-website/.cursor/rules/payload-overview.md new file mode 100644 index 00000000000..290c47822ab --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/payload-overview.md @@ -0,0 +1,126 @@ +--- +title: Payload CMS Overview +description: Core principles and quick reference for Payload CMS development +tags: [payload, overview, quickstart] +--- + +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Quick Reference + +| Task | Solution | +| --------------------- | ---------------------------------- | +| Auto-generate slugs | `slugField()` | +| Restrict by user | Access control with query | +| Local API user ops | `user` + `overrideAccess: false` | +| Draft/publish | `versions: { drafts: true }` | +| Computed fields | `virtual: true` with afterRead | +| Conditional fields | `admin.condition` | +| Custom validation | `validate` function | +| Filter relationships | `filterOptions` on field | +| Select fields | `select` parameter | +| Auto-set dates | beforeChange hook | +| Prevent loops | `req.context` check | +| Cascading deletes | beforeDelete hook | +| Geospatial queries | `point` field with `near`/`within` | +| Reverse relationships | `join` field type | +| Query relationships | Nested property syntax | +| Complex queries | AND/OR logic | +| Transactions | Pass `req` to operations | +| Background jobs | Jobs queue with tasks | +| Custom routes | Collection custom endpoints | +| Cloud storage | Storage adapter plugins | +| Multi-language | `localization` + `localized: true` | + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/with-vercel-website/.cursor/rules/plugin-development.md b/templates/with-vercel-website/.cursor/rules/plugin-development.md new file mode 100644 index 00000000000..d92bb12fb40 --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/plugin-development.md @@ -0,0 +1,323 @@ +--- +title: Plugin Development +description: Creating Payload CMS plugins with TypeScript patterns +tags: [payload, plugins, architecture, patterns] +--- + +# Payload Plugin Development + +## Plugin Architecture + +Plugins are functions that receive configuration options and return a function that transforms the Payload config: + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + enabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + // Transform config here + }) +``` + +**Key Pattern:** Double arrow function (currying) + +- First function: Accepts plugin options, returns plugin function +- Second function: Accepts Payload config, returns modified config + +## Adding Fields to Collections + +```typescript +export const seoPlugin = + (options: { collections?: string[] }): Plugin => + (config: Config): Config => { + const seoFields: Field[] = [ + { + name: 'meta', + type: 'group', + fields: [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ], + }, + ] + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...seoFields], + } + } + return collection + }), + } + } +``` + +## Adding New Collections + +```typescript +export const redirectsPlugin = + (options: { overrides?: Partial }): Plugin => + (config: Config): Config => { + const redirectsCollection: CollectionConfig = { + slug: 'redirects', + access: { read: () => true }, + fields: [ + { name: 'from', type: 'text', required: true, unique: true }, + { name: 'to', type: 'text', required: true }, + ], + ...options.overrides, + } + + return { + ...config, + collections: [...(config.collections || []), redirectsCollection], + } + } +``` + +## Adding Hooks + +```typescript +const resaveChildrenHook: CollectionAfterChangeHook = async ({ doc, req, operation }) => { + if (operation === 'update') { + const children = await req.payload.find({ + collection: 'pages', + where: { parent: { equals: doc.id } }, + }) + + for (const child of children.docs) { + await req.payload.update({ + collection: 'pages', + id: child.id, + data: child, + }) + } + } + return doc +} + +export const nestedDocsPlugin = + (options: { collections: string[] }): Plugin => + (config: Config): Config => ({ + ...config, + collections: (config.collections || []).map((collection) => { + if (options.collections.includes(collection.slug)) { + return { + ...collection, + hooks: { + ...(collection.hooks || {}), + afterChange: [resaveChildrenHook, ...(collection.hooks?.afterChange || [])], + }, + } + } + return collection + }), + }) +``` + +## Adding Root-Level Endpoints + +```typescript +export const seoPlugin = + (options: { generateTitle?: (doc: any) => string }): Plugin => + (config: Config): Config => { + const generateTitleEndpoint: Endpoint = { + path: '/plugin-seo/generate-title', + method: 'post', + handler: async (req) => { + const data = await req.json?.() + const result = options.generateTitle ? options.generateTitle(data.doc) : '' + return Response.json({ result }) + }, + } + + return { + ...config, + endpoints: [...(config.endpoints ?? []), generateTitleEndpoint], + } + } +``` + +## Field Overrides with Defaults + +```typescript +type FieldsOverride = (args: { defaultFields: Field[] }) => Field[] + +interface PluginConfig { + collections?: string[] + fields?: FieldsOverride +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const defaultFields: Field[] = [ + { name: 'title', type: 'text' }, + { name: 'description', type: 'textarea' }, + ] + + const fields = + options.fields && typeof options.fields === 'function' + ? options.fields({ defaultFields }) + : defaultFields + + return { + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...(collection.fields || []), ...fields], + } + } + return collection + }), + } + } +``` + +## Disable Plugin Pattern + +```typescript +interface PluginConfig { + disabled?: boolean + collections?: string[] +} + +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + // Always add collections/fields for database schema consistency + if (!config.collections) { + config.collections = [] + } + + config.collections.push({ + slug: 'plugin-collection', + fields: [{ name: 'title', type: 'text' }], + }) + + // If disabled, return early but keep schema changes + if (options.disabled) { + return config + } + + // Add endpoints, hooks, components only when enabled + config.endpoints = [ + ...(config.endpoints ?? []), + { + path: '/my-endpoint', + method: 'get', + handler: async () => Response.json({ message: 'Hello' }), + }, + ] + + return config + } +``` + +## Admin Components + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + if (!config.admin) config.admin = {} + if (!config.admin.components) config.admin.components = {} + if (!config.admin.components.beforeDashboard) { + config.admin.components.beforeDashboard = [] + } + + // Add client component + config.admin.components.beforeDashboard.push('my-plugin-name/client#BeforeDashboardClient') + + // Add server component (RSC) + config.admin.components.beforeDashboard.push('my-plugin-name/rsc#BeforeDashboardServer') + + return config + } +``` + +## onInit Hook + +```typescript +export const myPlugin = + (options: PluginConfig): Plugin => + (config: Config): Config => { + const incomingOnInit = config.onInit + + config.onInit = async (payload) => { + // IMPORTANT: Call existing onInit first + if (incomingOnInit) await incomingOnInit(payload) + + // Plugin initialization + payload.logger.info('Plugin initialized') + + // Example: Seed data + const { totalDocs } = await payload.count({ + collection: 'plugin-collection', + where: { id: { equals: 'seeded-by-plugin' } }, + }) + + if (totalDocs === 0) { + await payload.create({ + collection: 'plugin-collection', + data: { id: 'seeded-by-plugin' }, + }) + } + } + + return config + } +``` + +## Best Practices + +### Preserve Existing Config + +```typescript +// ✅ Good +collections: [...(config.collections || []), newCollection] + +// ❌ Bad +collections: [newCollection] +``` + +### Respect User Overrides + +```typescript +const collection: CollectionConfig = { + slug: 'redirects', + fields: defaultFields, + ...options.overrides, // User overrides last +} +``` + +### Hook Composition + +```typescript +hooks: { + ...collection.hooks, + afterChange: [ + myHook, + ...(collection.hooks?.afterChange || []), + ], +} +``` + +### Type Safety + +```typescript +import type { Config, Plugin, CollectionConfig, Field } from 'payload' +``` diff --git a/templates/with-vercel-website/.cursor/rules/queries.md b/templates/with-vercel-website/.cursor/rules/queries.md new file mode 100644 index 00000000000..4920ec85f09 --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/queries.md @@ -0,0 +1,223 @@ +--- +title: Queries +description: Local API, REST, and GraphQL query patterns +tags: [payload, queries, local-api, rest, graphql] +--- + +# Payload CMS Queries + +## Query Operators + +```typescript +// Equals +{ color: { equals: 'blue' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater/less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In/not in +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (point fields) +{ location: { near: [10, 20, 5000] } } // [lng, lat, maxDistance] +``` + +## AND/OR Logic + +```typescript +{ + or: [ + { color: { equals: 'mint' } }, + { + and: [ + { color: { equals: 'white' } }, + { featured: { equals: false } }, + ], + }, + ], +} +``` + +## Nested Properties + +```typescript +{ + 'author.role': { equals: 'editor' }, + 'meta.featured': { exists: true }, +} +``` + +## Local API + +```typescript +// Find documents +const posts = await payload.find({ + collection: 'posts', + where: { + status: { equals: 'published' }, + 'author.name': { contains: 'john' }, + }, + depth: 2, // Populate relationships + limit: 10, + page: 1, + sort: '-createdAt', + locale: 'en', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const post = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { + status: 'published', + }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) + +// Count +const count = await payload.count({ + collection: 'posts', + where: { + status: { equals: 'published' }, + }, +}) +``` + +## Access Control in Local API + +**CRITICAL**: Local API bypasses access control by default (`overrideAccess: true`). + +```typescript +// ❌ WRONG: User is passed but access control is bypassed +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + // Result: Operation runs with ADMIN privileges +}) + +// ✅ CORRECT: Respects user's access control permissions +const posts = await payload.find({ + collection: 'posts', + user: currentUser, + overrideAccess: false, // Required to enforce access control +}) + +// Administrative operation (intentionally bypass access control) +const allPosts = await payload.find({ + collection: 'posts', + // No user parameter, overrideAccess defaults to true +}) +``` + +**When to use `overrideAccess: false`:** + +- Performing operations on behalf of a user +- Testing access control logic +- API routes that should respect user permissions + +## REST API + +```typescript +import { stringify } from 'qs-esm' + +const query = { + status: { equals: 'published' }, +} + +const queryString = stringify( + { + where: query, + depth: 2, + limit: 10, + }, + { addQueryPrefix: true }, +) + +const response = await fetch(`https://api.example.com/api/posts${queryString}`) +const data = await response.json() +``` + +### REST Endpoints + +``` +GET /api/{collection} - Find documents +GET /api/{collection}/{id} - Find by ID +POST /api/{collection} - Create +PATCH /api/{collection}/{id} - Update +DELETE /api/{collection}/{id} - Delete +GET /api/{collection}/count - Count documents + +GET /api/globals/{slug} - Get global +POST /api/globals/{slug} - Update global +``` + +## GraphQL + +```graphql +query { + Posts(where: { status: { equals: published } }, limit: 10, sort: "-createdAt") { + docs { + id + title + author { + name + } + } + totalDocs + hasNextPage + } +} + +mutation { + createPost(data: { title: "New Post", status: draft }) { + id + title + } +} +``` + +## Performance Best Practices + +- Set `maxDepth` on relationships to prevent over-fetching +- Use `select` to limit returned fields +- Index frequently queried fields +- Use `virtual` fields for computed data +- Cache expensive operations in hook `context` diff --git a/templates/with-vercel-website/.cursor/rules/security-critical.mdc b/templates/with-vercel-website/.cursor/rules/security-critical.mdc new file mode 100644 index 00000000000..adf5d9e225d --- /dev/null +++ b/templates/with-vercel-website/.cursor/rules/security-critical.mdc @@ -0,0 +1,122 @@ +--- +title: Critical Security Patterns +description: The three most important security patterns in Payload CMS +tags: [payload, security, critical, access-control, transactions, hooks] +priority: high +--- + +# CRITICAL SECURITY PATTERNS + +These are the three most critical security patterns that MUST be followed in every Payload CMS project. + +## 1. Local API Access Control (MOST IMPORTANT) + +**By default, Local API operations bypass ALL access control**, even when passing a user. + +```typescript +// ❌ SECURITY BUG: Passes user but ignores their permissions +await payload.find({ + collection: 'posts', + user: someUser, // Access control is BYPASSED! +}) + +// ✅ SECURE: Actually enforces the user's permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED for access control +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**When to use each:** + +- `overrideAccess: true` (default) - Server-side operations you trust (cron jobs, system tasks) +- `overrideAccess: false` - When operating on behalf of a user (API routes, webhooks) + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +## 2. Transaction Safety in Hooks + +**Nested operations in hooks without `req` break transaction atomicity.** + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ] +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ] +} +``` + +**Why This Matters:** + +- **MongoDB (with replica sets)**: Creates atomic session across operations +- **PostgreSQL**: All operations use same Drizzle transaction +- **SQLite (with transactions enabled)**: Ensures rollback on errors +- **Without req**: Each operation runs independently, breaking atomicity + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +## 3. Prevent Infinite Hook Loops + +**Hooks triggering operations that trigger the same hooks create infinite loops.** + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ] +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ] +} +``` + +**Rule**: Use `req.context` flags to prevent hook loops diff --git a/templates/with-vercel-website/AGENTS.md b/templates/with-vercel-website/AGENTS.md new file mode 100644 index 00000000000..633b29b1f61 --- /dev/null +++ b/templates/with-vercel-website/AGENTS.md @@ -0,0 +1,1141 @@ +# Payload CMS Development Rules + +You are an expert Payload CMS developer. When working with Payload projects, follow these rules: + +## Core Principles + +1. **TypeScript-First**: Always use TypeScript with proper types from Payload +2. **Security-Critical**: Follow all security patterns, especially access control +3. **Type Generation**: Run `generate:types` script after schema changes +4. **Transaction Safety**: Always pass `req` to nested operations in hooks +5. **Access Control**: Understand Local API bypasses access control by default +6. **Access Control**: Ensure roles exist when modifiyng collection or globals with access controls + +### Code Validation + +- To validate typescript correctness after modifying code run `tsc --noEmit` +- Generate import maps after creating or modifying components. + +## Project Structure + +``` +src/ +├── app/ +│ ├── (frontend)/ # Frontend routes +│ └── (payload)/ # Payload admin routes +├── collections/ # Collection configs +├── globals/ # Global configs +├── components/ # Custom React components +├── hooks/ # Hook functions +├── access/ # Access control functions +└── payload.config.ts # Main config +``` + +## Configuration + +### Minimal Config Pattern + +```typescript +import { buildConfig } from 'payload' +import { mongooseAdapter } from '@payloadcms/db-mongodb' +import { lexicalEditor } from '@payloadcms/richtext-lexical' +import path from 'path' +import { fileURLToPath } from 'url' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfig({ + admin: { + user: 'users', + importMap: { + baseDir: path.resolve(dirname), + }, + }, + collections: [Users, Media], + editor: lexicalEditor(), + secret: process.env.PAYLOAD_SECRET, + typescript: { + outputFile: path.resolve(dirname, 'payload-types.ts'), + }, + db: mongooseAdapter({ + url: process.env.DATABASE_URI, + }), +}) +``` + +## Collections + +### Basic Collection + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + defaultColumns: ['title', 'author', 'status', 'createdAt'], + }, + fields: [ + { name: 'title', type: 'text', required: true }, + { name: 'slug', type: 'text', unique: true, index: true }, + { name: 'content', type: 'richText' }, + { name: 'author', type: 'relationship', relationTo: 'users' }, + ], + timestamps: true, +} +``` + +### Auth Collection with RBAC + +```typescript +export const Users: CollectionConfig = { + slug: 'users', + auth: true, + fields: [ + { + name: 'roles', + type: 'select', + hasMany: true, + options: ['admin', 'editor', 'user'], + defaultValue: ['user'], + required: true, + saveToJWT: true, // Include in JWT for fast access checks + access: { + update: ({ req: { user } }) => user?.roles?.includes('admin'), + }, + }, + ], +} +``` + +## Fields + +### Common Patterns + +```typescript +// Auto-generate slugs +import { slugField } from 'payload' +slugField({ fieldToUse: 'title' }) + +// Relationship with filtering +{ + name: 'category', + type: 'relationship', + relationTo: 'categories', + filterOptions: { active: { equals: true } }, +} + +// Conditional field +{ + name: 'featuredImage', + type: 'upload', + relationTo: 'media', + admin: { + condition: (data) => data.featured === true, + }, +} + +// Virtual field +{ + name: 'fullName', + type: 'text', + virtual: true, + hooks: { + afterRead: [({ siblingData }) => `${siblingData.firstName} ${siblingData.lastName}`], + }, +} +``` + +## CRITICAL SECURITY PATTERNS + +### 1. Local API Access Control (MOST IMPORTANT) + +```typescript +// ❌ SECURITY BUG: Access control bypassed +await payload.find({ + collection: 'posts', + user: someUser, // Ignored! Operation runs with ADMIN privileges +}) + +// ✅ SECURE: Enforces user permissions +await payload.find({ + collection: 'posts', + user: someUser, + overrideAccess: false, // REQUIRED +}) + +// ✅ Administrative operation (intentional bypass) +await payload.find({ + collection: 'posts', + // No user, overrideAccess defaults to true +}) +``` + +**Rule**: When passing `user` to Local API, ALWAYS set `overrideAccess: false` + +### 2. Transaction Safety in Hooks + +```typescript +// ❌ DATA CORRUPTION RISK: Separate transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + // Missing req - runs in separate transaction! + }) + }, + ], +} + +// ✅ ATOMIC: Same transaction +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.create({ + collection: 'audit-log', + data: { docId: doc.id }, + req, // Maintains atomicity + }) + }, + ], +} +``` + +**Rule**: ALWAYS pass `req` to nested operations in hooks + +### 3. Prevent Infinite Hook Loops + +```typescript +// ❌ INFINITE LOOP +hooks: { + afterChange: [ + async ({ doc, req }) => { + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + req, + }) // Triggers afterChange again! + }, + ], +} + +// ✅ SAFE: Use context flag +hooks: { + afterChange: [ + async ({ doc, req, context }) => { + if (context.skipHooks) return + + await req.payload.update({ + collection: 'posts', + id: doc.id, + data: { views: doc.views + 1 }, + context: { skipHooks: true }, + req, + }) + }, + ], +} +``` + +## Access Control + +### Collection-Level Access + +```typescript +import type { Access } from 'payload' + +// Boolean return +const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Query constraint (row-level security) +const ownPostsOnly: Access = ({ req: { user } }) => { + if (!user) return false + if (user?.roles?.includes('admin')) return true + + return { + author: { equals: user.id }, + } +} + +// Async access check +const projectMemberAccess: Access = async ({ req, id }) => { + const { user, payload } = req + + if (!user) return false + if (user.roles?.includes('admin')) return true + + const project = await payload.findByID({ + collection: 'projects', + id: id as string, + depth: 0, + }) + + return project.members?.includes(user.id) +} +``` + +### Field-Level Access + +```typescript +// Field access ONLY returns boolean (no query constraints) +{ + name: 'salary', + type: 'number', + access: { + read: ({ req: { user }, doc }) => { + // Self can read own salary + if (user?.id === doc?.id) return true + // Admin can read all + return user?.roles?.includes('admin') + }, + update: ({ req: { user } }) => { + // Only admins can update + return user?.roles?.includes('admin') + }, + }, +} +``` + +### Common Access Patterns + +```typescript +// Anyone +export const anyone: Access = () => true + +// Authenticated only +export const authenticated: Access = ({ req: { user } }) => Boolean(user) + +// Admin only +export const adminOnly: Access = ({ req: { user } }) => { + return user?.roles?.includes('admin') +} + +// Admin or self +export const adminOrSelf: Access = ({ req: { user } }) => { + if (user?.roles?.includes('admin')) return true + return { id: { equals: user?.id } } +} + +// Published or authenticated +export const authenticatedOrPublished: Access = ({ req: { user } }) => { + if (user) return true + return { _status: { equals: 'published' } } +} +``` + +## Hooks + +### Common Hook Patterns + +```typescript +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + hooks: { + // Before validation - format data + beforeValidate: [ + async ({ data, operation }) => { + if (operation === 'create') { + data.slug = slugify(data.title) + } + return data + }, + ], + + // Before save - business logic + beforeChange: [ + async ({ data, req, operation, originalDoc }) => { + if (operation === 'update' && data.status === 'published') { + data.publishedAt = new Date() + } + return data + }, + ], + + // After save - side effects + afterChange: [ + async ({ doc, req, operation, previousDoc, context }) => { + // Check context to prevent loops + if (context.skipNotification) return + + if (operation === 'create') { + await sendNotification(doc) + } + return doc + }, + ], + + // After read - computed fields + afterRead: [ + async ({ doc, req }) => { + doc.viewCount = await getViewCount(doc.id) + return doc + }, + ], + + // Before delete - cascading deletes + beforeDelete: [ + async ({ req, id }) => { + await req.payload.delete({ + collection: 'comments', + where: { post: { equals: id } }, + req, // Important for transaction + }) + }, + ], + }, +} +``` + +## Queries + +### Local API + +```typescript +// Find with complex query +const posts = await payload.find({ + collection: 'posts', + where: { + and: [{ status: { equals: 'published' } }, { 'author.name': { contains: 'john' } }], + }, + depth: 2, // Populate relationships + limit: 10, + sort: '-createdAt', + select: { + title: true, + author: true, + }, +}) + +// Find by ID +const post = await payload.findByID({ + collection: 'posts', + id: '123', + depth: 2, +}) + +// Create +const newPost = await payload.create({ + collection: 'posts', + data: { + title: 'New Post', + status: 'draft', + }, +}) + +// Update +await payload.update({ + collection: 'posts', + id: '123', + data: { status: 'published' }, +}) + +// Delete +await payload.delete({ + collection: 'posts', + id: '123', +}) +``` + +### Query Operators + +```typescript +// Equals +{ status: { equals: 'published' } } + +// Not equals +{ status: { not_equals: 'draft' } } + +// Greater than / less than +{ price: { greater_than: 100 } } +{ age: { less_than_equal: 65 } } + +// Contains (case-insensitive) +{ title: { contains: 'payload' } } + +// Like (all words present) +{ description: { like: 'cms headless' } } + +// In array +{ category: { in: ['tech', 'news'] } } + +// Exists +{ image: { exists: true } } + +// Near (geospatial) +{ location: { near: [-122.4194, 37.7749, 10000] } } +``` + +### AND/OR Logic + +```typescript +{ + or: [ + { status: { equals: 'published' } }, + { author: { equals: user.id } }, + ], +} + +{ + and: [ + { status: { equals: 'published' } }, + { featured: { equals: true } }, + ], +} +``` + +## Getting Payload Instance + +```typescript +// In API routes (Next.js) +import { getPayload } from 'payload' +import config from '@payload-config' + +export async function GET() { + const payload = await getPayload({ config }) + + const posts = await payload.find({ + collection: 'posts', + }) + + return Response.json(posts) +} + +// In Server Components +import { getPayload } from 'payload' +import config from '@payload-config' + +export default async function Page() { + const payload = await getPayload({ config }) + const { docs } = await payload.find({ collection: 'posts' }) + + return
{docs.map(post =>

{post.title}

)}
+} +``` + +## Components + +The Admin Panel can be extensively customized using React Components. Custom Components can be Server Components (default) or Client Components. + +### Defining Components + +Components are defined using **file paths** (not direct imports) in your config: + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +```typescript +import { buildConfig } from 'payload' + +export default buildConfig({ + admin: { + components: { + // Logo and branding + graphics: { + Logo: '/components/Logo', + Icon: '/components/Icon', + }, + + // Navigation + Nav: '/components/CustomNav', + beforeNavLinks: ['/components/CustomNavItem'], + afterNavLinks: ['/components/NavFooter'], + + // Header + header: ['/components/AnnouncementBanner'], + actions: ['/components/ClearCache', '/components/Preview'], + + // Dashboard + beforeDashboard: ['/components/WelcomeMessage'], + afterDashboard: ['/components/Analytics'], + + // Auth + beforeLogin: ['/components/SSOButtons'], + logout: { Button: '/components/LogoutButton' }, + + // Settings + settingsMenu: ['/components/SettingsMenu'], + + // Views + views: { + dashboard: { Component: '/components/CustomDashboard' }, + }, + }, + }, +}) +``` + +**Component Path Rules:** + +- Paths are relative to project root or `config.admin.importMap.baseDir` +- Named exports: use `#ExportName` suffix or `exportName` property +- Default exports: no suffix needed +- File extensions can be omitted + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Component Types + +1. **Root Components** - Global Admin Panel (logo, nav, header) +2. **Collection Components** - Collection-specific (edit view, list view) +3. **Global Components** - Global document views +4. **Field Components** - Custom field UI and cells + +### Server vs Client Components + +**All components are Server Components by default** (can use Local API directly): + +```tsx +// Server Component (default) +import type { Payload } from 'payload' + +async function MyServerComponent({ payload }: { payload: Payload }) { + const posts = await payload.find({ collection: 'posts' }) + return
{posts.totalDocs} posts
+} + +export default MyServerComponent +``` + +**Client Components** need the `'use client'` directive: + +```tsx +'use client' +import { useState } from 'react' +import { useAuth } from '@payloadcms/ui' + +export function MyClientComponent() { + const [count, setCount] = useState(0) + const { user } = useAuth() + + return ( + + ) +} +``` + +### Using Hooks (Client Components Only) + +```tsx +'use client' +import { + useAuth, // Current user + useConfig, // Payload config (client-safe) + useDocumentInfo, // Document info (id, collection, etc.) + useField, // Field value and setter + useForm, // Form state + useFormFields, // Multiple field values (optimized) + useLocale, // Current locale + useTranslation, // i18n translations + usePayload, // Local API methods +} from '@payloadcms/ui' + +export function MyComponent() { + const { user } = useAuth() + const { config } = useConfig() + const { id, collection } = useDocumentInfo() + const locale = useLocale() + const { t } = useTranslation() + + return
Hello {user?.email}
+} +``` + +### Collection/Global Components + +```typescript +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + components: { + // Edit view + edit: { + PreviewButton: '/components/PostPreview', + SaveButton: '/components/CustomSave', + SaveDraftButton: '/components/SaveDraft', + PublishButton: '/components/Publish', + }, + + // List view + list: { + Header: '/components/ListHeader', + beforeList: ['/components/BulkActions'], + afterList: ['/components/ListFooter'], + }, + }, + }, +} +``` + +### Field Components + +```typescript +{ + name: 'status', + type: 'select', + options: ['draft', 'published'], + admin: { + components: { + // Edit view field + Field: '/components/StatusField', + // List view cell + Cell: '/components/StatusCell', + // Field label + Label: '/components/StatusLabel', + // Field description + Description: '/components/StatusDescription', + // Error message + Error: '/components/StatusError', + }, + }, +} +``` + +**UI Field** (presentational only, no data): + +```typescript +{ + name: 'refundButton', + type: 'ui', + admin: { + components: { + Field: '/components/RefundButton', + }, + }, +} +``` + +### Performance Best Practices + +1. **Import correctly:** + + - Admin Panel: `import { Button } from '@payloadcms/ui'` + - Frontend: `import { Button } from '@payloadcms/ui/elements/Button'` + +2. **Optimize re-renders:** + + ```tsx + // ❌ BAD: Re-renders on every form change + const { fields } = useForm() + + // ✅ GOOD: Only re-renders when specific field changes + const value = useFormFields(([fields]) => fields[path]) + ``` + +3. **Prefer Server Components** - Only use Client Components when you need: + + - State (useState, useReducer) + - Effects (useEffect) + - Event handlers (onClick, onChange) + - Browser APIs (localStorage, window) + +4. **Minimize serialized props** - Server Components serialize props sent to client + +### Styling Components + +```tsx +import './styles.scss' + +export function MyComponent() { + return
Content
+} +``` + +```scss +// Use Payload's CSS variables +.my-component { + background-color: var(--theme-elevation-500); + color: var(--theme-text); + padding: var(--base); + border-radius: var(--border-radius-m); +} + +// Import Payload's SCSS library +@import '~@payloadcms/ui/scss'; + +.my-component { + @include mid-break { + background-color: var(--theme-elevation-900); + } +} +``` + +### Type Safety + +```tsx +import type { + TextFieldServerComponent, + TextFieldClientComponent, + TextFieldCellComponent, + SelectFieldServerComponent, + // ... etc +} from 'payload' + +export const MyField: TextFieldClientComponent = (props) => { + // Fully typed props +} +``` + +### Import Map + +Payload auto-generates `app/(payload)/admin/importMap.js` to resolve component paths. + +**Regenerate manually:** + +```bash +payload generate:importmap +``` + +**Set custom location:** + +```typescript +export default buildConfig({ + admin: { + importMap: { + baseDir: path.resolve(dirname, 'src'), + importMapFile: path.resolve(dirname, 'app', 'custom-import-map.js'), + }, + }, +}) +``` + +## Custom Endpoints + +```typescript +import type { Endpoint } from 'payload' +import { APIError } from 'payload' + +// Always check authentication +export const protectedEndpoint: Endpoint = { + path: '/protected', + method: 'get', + handler: async (req) => { + if (!req.user) { + throw new APIError('Unauthorized', 401) + } + + // Use req.payload for database operations + const data = await req.payload.find({ + collection: 'posts', + where: { author: { equals: req.user.id } }, + }) + + return Response.json(data) + }, +} + +// Route parameters +export const trackingEndpoint: Endpoint = { + path: '/:id/tracking', + method: 'get', + handler: async (req) => { + const { id } = req.routeParams + + const tracking = await getTrackingInfo(id) + + if (!tracking) { + return Response.json({ error: 'not found' }, { status: 404 }) + } + + return Response.json(tracking) + }, +} +``` + +## Drafts & Versions + +```typescript +export const Pages: CollectionConfig = { + slug: 'pages', + versions: { + drafts: { + autosave: true, + schedulePublish: true, + validate: false, // Don't validate drafts + }, + maxPerDoc: 100, + }, + access: { + read: ({ req: { user } }) => { + // Public sees only published + if (!user) return { _status: { equals: 'published' } } + // Authenticated sees all + return true + }, + }, +} + +// Create draft +await payload.create({ + collection: 'pages', + data: { title: 'Draft Page' }, + draft: true, // Skips required field validation +}) + +// Read with drafts +const page = await payload.findByID({ + collection: 'pages', + id: '123', + draft: true, // Returns draft if available +}) +``` + +## Field Type Guards + +```typescript +import { + fieldAffectsData, + fieldHasSubFields, + fieldIsArrayType, + fieldIsBlockType, + fieldSupportsMany, + fieldHasMaxDepth, +} from 'payload' + +function processField(field: Field) { + // Check if field stores data + if (fieldAffectsData(field)) { + console.log(field.name) // Safe to access + } + + // Check if field has nested fields + if (fieldHasSubFields(field)) { + field.fields.forEach(processField) // Safe to access + } + + // Check field type + if (fieldIsArrayType(field)) { + console.log(field.minRows, field.maxRows) + } + + // Check capabilities + if (fieldSupportsMany(field) && field.hasMany) { + console.log('Multiple values supported') + } +} +``` + +## Plugins + +### Using Plugins + +```typescript +import { seoPlugin } from '@payloadcms/plugin-seo' +import { redirectsPlugin } from '@payloadcms/plugin-redirects' + +export default buildConfig({ + plugins: [ + seoPlugin({ + collections: ['posts', 'pages'], + }), + redirectsPlugin({ + collections: ['pages'], + }), + ], +}) +``` + +### Creating Plugins + +```typescript +import type { Config, Plugin } from 'payload' + +interface MyPluginConfig { + collections?: string[] + enabled?: boolean +} + +export const myPlugin = + (options: MyPluginConfig): Plugin => + (config: Config): Config => ({ + ...config, + collections: config.collections?.map((collection) => { + if (options.collections?.includes(collection.slug)) { + return { + ...collection, + fields: [...collection.fields, { name: 'pluginField', type: 'text' }], + } + } + return collection + }), + }) +``` + +## Best Practices + +### Security + +1. Always set `overrideAccess: false` when passing `user` to Local API +2. Field-level access only returns boolean (no query constraints) +3. Default to restrictive access, gradually add permissions +4. Never trust client-provided data +5. Use `saveToJWT: true` for roles to avoid database lookups + +### Performance + +1. Index frequently queried fields +2. Use `select` to limit returned fields +3. Set `maxDepth` on relationships to prevent over-fetching +4. Use query constraints over async operations in access control +5. Cache expensive operations in `req.context` + +### Data Integrity + +1. Always pass `req` to nested operations in hooks +2. Use context flags to prevent infinite hook loops +3. Enable transactions for MongoDB (requires replica set) and Postgres +4. Use `beforeValidate` for data formatting +5. Use `beforeChange` for business logic + +### Type Safety + +1. Run `generate:types` after schema changes +2. Import types from generated `payload-types.ts` +3. Type your user object: `import type { User } from '@/payload-types'` +4. Use `as const` for field options +5. Use field type guards for runtime type checking + +### Organization + +1. Keep collections in separate files +2. Extract access control to `access/` directory +3. Extract hooks to `hooks/` directory +4. Use reusable field factories for common patterns +5. Document complex access control with comments + +## Common Gotchas + +1. **Local API Default**: Access control bypassed unless `overrideAccess: false` +2. **Transaction Safety**: Missing `req` in nested operations breaks atomicity +3. **Hook Loops**: Operations in hooks can trigger the same hooks +4. **Field Access**: Cannot use query constraints, only boolean +5. **Relationship Depth**: Default depth is 2, set to 0 for IDs only +6. **Draft Status**: `_status` field auto-injected when drafts enabled +7. **Type Generation**: Types not updated until `generate:types` runs +8. **MongoDB Transactions**: Require replica set configuration +9. **SQLite Transactions**: Disabled by default, enable with `transactionOptions: {}` +10. **Point Fields**: Not supported in SQLite + +## Additional Context Files + +For deeper exploration of specific topics, refer to the context files located in `.cursor/rules/`: + +### Available Context Files + +1. **`payload-overview.md`** - High-level architecture and core concepts + + - Payload structure and initialization + - Configuration fundamentals + - Database adapters overview + +2. **`security-critical.md`** - Critical security patterns (⚠️ IMPORTANT) + + - Local API access control + - Transaction safety in hooks + - Preventing infinite hook loops + +3. **`collections.md`** - Collection configurations + + - Basic collection patterns + - Auth collections with RBAC + - Upload collections + - Drafts and versioning + - Globals + +4. **`fields.md`** - Field types and patterns + + - All field types with examples + - Conditional fields + - Virtual fields + - Field validation + - Common field patterns + +5. **`field-type-guards.md`** - TypeScript field type utilities + + - Field type checking utilities + - Safe type narrowing + - Runtime field validation + +6. **`access-control.md`** - Permission patterns + + - Collection-level access + - Field-level access + - Row-level security + - RBAC patterns + - Multi-tenant access control + +7. **`access-control-advanced.md`** - Complex access patterns + + - Nested document access + - Cross-collection permissions + - Dynamic role hierarchies + - Performance optimization + +8. **`hooks.md`** - Lifecycle hooks + + - Collection hooks + - Field hooks + - Hook context patterns + - Common hook recipes + +9. **`queries.md`** - Database operations + + - Local API usage + - Query operators + - Complex queries with AND/OR + - Performance optimization + +10. **`endpoints.md`** - Custom API endpoints + + - REST endpoint patterns + - Authentication in endpoints + - Error handling + - Route parameters + +11. **`adapters.md`** - Database and storage adapters + + - MongoDB, PostgreSQL, SQLite patterns + - Storage adapter usage (S3, Azure, GCS, etc.) + - Custom adapter development + +12. **`plugin-development.md`** - Creating plugins + + - Plugin architecture + - Modifying configuration + - Plugin hooks + - Best practices + +13. **`components.md`** - Custom Components + + - Component types (Root, Collection, Global, Field) + - Server vs Client Components + - Component paths and definition + - Default and custom props + - Using hooks + - Performance best practices + - Styling components + +## Resources + +- Docs: https://payloadcms.com/docs +- LLM Context: https://payloadcms.com/llms-full.txt +- GitHub: https://github.com/payloadcms/payload +- Examples: https://github.com/payloadcms/payload/tree/main/examples +- Templates: https://github.com/payloadcms/payload/tree/main/templates diff --git a/templates/with-vercel-website/package.json b/templates/with-vercel-website/package.json index e2343ae1945..46b657895c0 100644 --- a/templates/with-vercel-website/package.json +++ b/templates/with-vercel-website/package.json @@ -23,18 +23,18 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/admin-bar": "3.63.0", - "@payloadcms/db-vercel-postgres": "3.63.0", - "@payloadcms/live-preview-react": "3.63.0", - "@payloadcms/next": "3.63.0", - "@payloadcms/plugin-form-builder": "3.63.0", - "@payloadcms/plugin-nested-docs": "3.63.0", - "@payloadcms/plugin-redirects": "3.63.0", - "@payloadcms/plugin-search": "3.63.0", - "@payloadcms/plugin-seo": "3.63.0", - "@payloadcms/richtext-lexical": "3.63.0", - "@payloadcms/storage-vercel-blob": "3.63.0", - "@payloadcms/ui": "3.63.0", + "@payloadcms/admin-bar": "3.68.5", + "@payloadcms/db-vercel-postgres": "3.68.5", + "@payloadcms/live-preview-react": "3.68.5", + "@payloadcms/next": "3.68.5", + "@payloadcms/plugin-form-builder": "3.68.5", + "@payloadcms/plugin-nested-docs": "3.68.5", + "@payloadcms/plugin-redirects": "3.68.5", + "@payloadcms/plugin-search": "3.68.5", + "@payloadcms/plugin-seo": "3.68.5", + "@payloadcms/richtext-lexical": "3.68.5", + "@payloadcms/storage-vercel-blob": "3.68.5", + "@payloadcms/ui": "3.68.5", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-select": "^2.0.0", @@ -48,7 +48,7 @@ "lucide-react": "^0.378.0", "next": "15.4.10", "next-sitemap": "^4.2.3", - "payload": "3.63.0", + "payload": "3.68.5", "prism-react-renderer": "^2.3.1", "react": "19.2.1", "react-dom": "19.2.1", @@ -81,7 +81,7 @@ "vite-tsconfig-paths": "5.1.4", "vitest": "3.2.3" }, - "packageManager": "pnpm@10.20.0", + "packageManager": "pnpm@10.26.0", "engines": { "node": "^18.20.2 || >=20.9.0" }, diff --git a/templates/with-vercel-website/src/migrations/20251107_183848_initial.json b/templates/with-vercel-website/src/migrations/20251216_194333_initial.json similarity index 99% rename from templates/with-vercel-website/src/migrations/20251107_183848_initial.json rename to templates/with-vercel-website/src/migrations/20251216_194333_initial.json index c9f38436b73..d5202681594 100644 --- a/templates/with-vercel-website/src/migrations/20251107_183848_initial.json +++ b/templates/with-vercel-website/src/migrations/20251216_194333_initial.json @@ -1,6 +1,4 @@ { - "id": "6686d861-e460-451a-b85d-51479253bd5e", - "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", "tables": { @@ -9182,5 +9180,7 @@ "schemas": {}, "tables": {}, "columns": {} - } + }, + "id": "39a710ea-5b17-43d5-bf1c-6010b856e4d7", + "prevId": "00000000-0000-0000-0000-000000000000" } diff --git a/templates/with-vercel-website/src/migrations/20251107_183848_initial.ts b/templates/with-vercel-website/src/migrations/20251216_194333_initial.ts similarity index 100% rename from templates/with-vercel-website/src/migrations/20251107_183848_initial.ts rename to templates/with-vercel-website/src/migrations/20251216_194333_initial.ts diff --git a/templates/with-vercel-website/src/migrations/index.ts b/templates/with-vercel-website/src/migrations/index.ts index 5487974cd87..9db85afa116 100644 --- a/templates/with-vercel-website/src/migrations/index.ts +++ b/templates/with-vercel-website/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20251107_183848_initial from './20251107_183848_initial' +import * as migration_20251216_194333_initial from './20251216_194333_initial' export const migrations = [ { - up: migration_20251107_183848_initial.up, - down: migration_20251107_183848_initial.down, - name: '20251107_183848_initial', + up: migration_20251216_194333_initial.up, + down: migration_20251216_194333_initial.down, + name: '20251216_194333_initial', }, ] diff --git a/templates/with-vercel-website/src/payload-types.ts b/templates/with-vercel-website/src/payload-types.ts index 3c214ec076c..a420f9aefc6 100644 --- a/templates/with-vercel-website/src/payload-types.ts +++ b/templates/with-vercel-website/src/payload-types.ts @@ -108,6 +108,7 @@ export interface Config { db: { defaultIDType: number; }; + fallbackLocale: null; globals: { header: Header; footer: Footer; diff --git a/templates/with-vercel-website/src/payload.config.ts b/templates/with-vercel-website/src/payload.config.ts index 461989c2f58..aa4fd34a0c0 100644 --- a/templates/with-vercel-website/src/payload.config.ts +++ b/templates/with-vercel-website/src/payload.config.ts @@ -1,4 +1,3 @@ -import { vercelBlobStorage } from '@payloadcms/storage-vercel-blob' import { vercelPostgresAdapter } from '@payloadcms/db-vercel-postgres' import sharp from 'sharp' import path from 'path' @@ -15,6 +14,7 @@ import { Header } from './Header/config' import { plugins } from './plugins' import { defaultLexical } from '@/fields/defaultLexical' import { getServerSideURL } from './utilities/getURL' +import { vercelBlobStorage } from '@payloadcms/storage-vercel-blob' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) @@ -65,7 +65,6 @@ export default buildConfig({ }), collections: [Pages, Posts, Media, Categories, Users], cors: [getServerSideURL()].filter(Boolean), - globals: [Header, Footer], plugins: [ ...plugins, vercelBlobStorage({ @@ -75,6 +74,7 @@ export default buildConfig({ token: process.env.BLOB_READ_WRITE_TOKEN || '', }), ], + globals: [Header, Footer], secret: process.env.PAYLOAD_SECRET, sharp, typescript: { diff --git a/tools/scripts/src/generate-template-variations.ts b/tools/scripts/src/generate-template-variations.ts index e2ecc94a679..680e190261f 100644 --- a/tools/scripts/src/generate-template-variations.ts +++ b/tools/scripts/src/generate-template-variations.ts @@ -47,6 +47,10 @@ type TemplateVariation = { * @default false */ skipReadme?: boolean + /** + * @default false + */ + skipAgents?: boolean storage: StorageAdapterType vercelDeployButtonLink?: string /** @@ -83,6 +87,7 @@ async function main() { sharp: false, skipDockerCompose: true, skipReadme: true, + skipAgents: false, storage: 'vercelBlobStorage', targetDeployment: 'vercel', vercelDeployButtonLink: @@ -107,6 +112,7 @@ async function main() { sharp: true, skipDockerCompose: true, skipReadme: true, + skipAgents: false, storage: 'vercelBlobStorage', targetDeployment: 'vercel', vercelDeployButtonLink: @@ -125,6 +131,7 @@ async function main() { dirname: 'with-postgres', sharp: true, skipDockerCompose: true, + skipAgents: false, storage: 'localDisk', }, { @@ -137,6 +144,7 @@ async function main() { sharp: false, storage: 'vercelBlobStorage', skipReadme: true, + skipAgents: false, targetDeployment: 'vercel', vercelDeployButtonLink: `https://vercel.com/new/clone?repository-url=` + @@ -157,6 +165,7 @@ async function main() { sharp: true, skipConfig: true, // Do not copy the payload.config.ts file from the base template skipReadme: true, // Do not copy the README.md file from the base template + skipAgents: false, storage: 'localDisk', // The blank template is used as a base for create-payload-app functionality, // so we do not configure the payload.config.ts file, which leaves the placeholder comments. @@ -171,6 +180,7 @@ async function main() { generateLockfile: true, sharp: true, skipConfig: true, // Do not copy the payload.config.ts file from the base template + skipAgents: false, storage: 'localDisk', // The blank template is used as a base for create-payload-app functionality, // so we do not configure the payload.config.ts file, which leaves the placeholder comments. @@ -187,6 +197,7 @@ async function main() { generateLockfile: true, sharp: true, skipConfig: true, // Do not copy the payload.config.ts file from the base template + skipAgents: false, storage: 'localDisk', // The blank template is used as a base for create-payload-app functionality, // so we do not configure the payload.config.ts file, which leaves the placeholder comments. @@ -203,6 +214,7 @@ async function main() { generateLockfile: false, sharp: false, skipConfig: true, // Do not copy the payload.config.ts file from the base template + skipAgents: false, storage: 'r2Storage', // The blank template is used as a base for create-payload-app functionality, // so we do not configure the payload.config.ts file, which leaves the placeholder comments. @@ -237,6 +249,7 @@ async function main() { skipConfig = false, skipDockerCompose = false, skipReadme = false, + skipAgents = false, storage, vercelDeployButtonLink, targetDeployment = 'default', @@ -260,6 +273,11 @@ async function main() { log(`Copied to ${destDir}`) + // Copy _agents files + if (!skipAgents) { + await copyAgentsFiles({ destDir }) + } + if (configureConfig !== false) { log('Configuring payload.config.ts') const configureArgs = { @@ -417,6 +435,34 @@ ${description} log('Generated README.md') } +async function copyAgentsFiles({ destDir }: { destDir: string }) { + const agentsSourceDir = path.join(TEMPLATES_DIR, '_agents') + + if (!(await fs.stat(agentsSourceDir).catch(() => null))) { + log(`Skipping agents copy: ${agentsSourceDir} does not exist`) + return + } + + log('Copying agents files') + + // Copy AGENTS.md + const agentsMdSource = path.join(agentsSourceDir, 'AGENTS.md') + const agentsMdDest = path.join(destDir, 'AGENTS.md') + if (await fs.stat(agentsMdSource).catch(() => null)) { + await fs.copyFile(agentsMdSource, agentsMdDest) + log('Copied AGENTS.md') + } + + // Copy .cursor directory + const cursorSourceDir = path.join(agentsSourceDir, 'rules') + const cursorDestDir = path.join(destDir, '.cursor', 'rules') + if (await fs.stat(cursorSourceDir).catch(() => null)) { + await fs.mkdir(path.dirname(cursorDestDir), { recursive: true }) + await fs.cp(cursorSourceDir, cursorDestDir, { recursive: true }) + log('Copied .cursor/rules/') + } +} + async function handleDeploymentTarget({ targetDeployment, destDir, From 0a6ba6f4fff38e0e62b8411149fa4c79f1102c78 Mon Sep 17 00:00:00 2001 From: Jens Becker Date: Wed, 17 Dec 2025 23:44:21 +0100 Subject: [PATCH 21/67] fix(storage-s3): encode filename in generated URL (#14438) ### What This PR updates the `getGenerateURL` function in the `s3-storage` adapter to properly encode filenames using `encodeURIComponent` when constructing file URLs. This ensures that the URL is properly encoded when using the `disablePayloadAccessControl` option. ### Why Without URL encoding, filenames containing special characters (spaces, unicode characters, special symbols, etc.) can break URL generation and lead to: - 404 errors when accessing files with special characters - Malformed URLs that don't properly resolve - Security issues with improperly escaped characters ### How The fix wraps the filename parameter with `encodeURIComponent()` in the URL construction, similar to how it is done in the [storage-vercel-blob package](https://github.com/payloadcms/payload/blob/53d85574d8405f45423871ccf1da3209371ad2da/packages/storage-vercel-blob/src/generateURL.ts#L12). ### Example: - Before: `https://s3.endpoint.com/bucket/my file.jpg` (breaks) - After: `https://s3.endpoint.com/bucket/my%20file.jpg` (works correctly) --- packages/storage-s3/src/generateURL.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/storage-s3/src/generateURL.ts b/packages/storage-s3/src/generateURL.ts index 358502e7e39..f7648461975 100644 --- a/packages/storage-s3/src/generateURL.ts +++ b/packages/storage-s3/src/generateURL.ts @@ -12,5 +12,5 @@ export const getGenerateURL = ({ bucket, config: { endpoint } }: Args): GenerateURL => ({ filename, prefix = '' }) => { const stringifiedEndpoint = typeof endpoint === 'string' ? endpoint : endpoint?.toString() - return `${stringifiedEndpoint}/${bucket}/${path.posix.join(prefix, filename)}` + return `${stringifiedEndpoint}/${bucket}/${path.posix.join(prefix, encodeURIComponent(filename))}` } From 0e81fdb6a4e9e842607ae7a47d88828132df523a Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 17 Dec 2025 17:24:47 -0600 Subject: [PATCH 22/67] chore(storage-s3): add int tests for filename encoding (#14970) Adds some int tests as a follow up to https://github.com/payloadcms/payload/pull/14438 --------- Co-authored-by: Jens Becker --- .../collections/MediaWithDirectAccess.ts | 15 ++++++ test/storage-s3/config.ts | 14 +++++- test/storage-s3/int.spec.ts | 44 ++++++++++++++++++ test/storage-s3/payload-types.ts | 44 ++++++++++++++++++ test/storage-s3/shared.ts | 1 + test/uploads/image with spaces.png | Bin 0 -> 89728 bytes 6 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 test/storage-s3/collections/MediaWithDirectAccess.ts create mode 100644 test/uploads/image with spaces.png diff --git a/test/storage-s3/collections/MediaWithDirectAccess.ts b/test/storage-s3/collections/MediaWithDirectAccess.ts new file mode 100644 index 00000000000..4c97aa00050 --- /dev/null +++ b/test/storage-s3/collections/MediaWithDirectAccess.ts @@ -0,0 +1,15 @@ +import type { CollectionConfig } from 'payload' + +export const MediaWithDirectAccess: CollectionConfig = { + slug: 'media-with-direct-access', + upload: { + disableLocalStorage: true, + }, + fields: [ + { + name: 'alt', + label: 'Alt Text', + type: 'text', + }, + ], +} diff --git a/test/storage-s3/config.ts b/test/storage-s3/config.ts index 339f3a6af26..941a39b8be8 100644 --- a/test/storage-s3/config.ts +++ b/test/storage-s3/config.ts @@ -6,12 +6,14 @@ import path from 'path' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { devUser } from '../credentials.js' import { Media } from './collections/Media.js' +import { MediaWithDirectAccess } from './collections/MediaWithDirectAccess.js' import { MediaWithDynamicPrefix } from './collections/MediaWithDynamicPrefix.js' import { MediaWithPrefix } from './collections/MediaWithPrefix.js' import { MediaWithSignedDownloads } from './collections/MediaWithSignedDownloads.js' import { Users } from './collections/Users.js' import { mediaSlug, + mediaWithDirectAccessSlug, mediaWithDynamicPrefixSlug, mediaWithPrefixSlug, mediaWithSignedDownloadsSlug, @@ -33,7 +35,14 @@ export default buildConfigWithDefaults({ baseDir: path.resolve(dirname), }, }, - collections: [Media, MediaWithDynamicPrefix, MediaWithPrefix, MediaWithSignedDownloads, Users], + collections: [ + Media, + MediaWithDirectAccess, + MediaWithDynamicPrefix, + MediaWithPrefix, + MediaWithSignedDownloads, + Users, + ], onInit: async (payload) => { await payload.create({ collection: 'users', @@ -47,6 +56,9 @@ export default buildConfigWithDefaults({ s3Storage({ collections: { [mediaSlug]: true, + [mediaWithDirectAccessSlug]: { + disablePayloadAccessControl: true, + }, [mediaWithDynamicPrefixSlug]: true, [mediaWithPrefixSlug]: { prefix, diff --git a/test/storage-s3/int.spec.ts b/test/storage-s3/int.spec.ts index eb33983a013..5c661ac4752 100644 --- a/test/storage-s3/int.spec.ts +++ b/test/storage-s3/int.spec.ts @@ -9,6 +9,7 @@ import type { NextRESTClient } from '../helpers/NextRESTClient.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' import { mediaSlug, + mediaWithDirectAccessSlug, mediaWithDynamicPrefixSlug, mediaWithPrefixSlug, mediaWithSignedDownloadsSlug, @@ -121,6 +122,49 @@ describe('@payloadcms/storage-s3', () => { expect(response.status).toBe(404) }) + describe('disablePayloadAccessControl', () => { + it('should return direct S3 URL with encoded filename when uploading file with spaces', async () => { + const upload = await payload.create({ + collection: mediaWithDirectAccessSlug, + data: {}, + filePath: path.resolve(dirname, '../uploads/image with spaces.png'), + }) + + expect(upload.id).toBeTruthy() + expect(upload.filename).toBe('image with spaces.png') + + // When disablePayloadAccessControl is true, URL should point directly to S3 + // and the filename should be URL-encoded + expect(upload.url).toContain(process.env.S3_ENDPOINT) + expect(upload.url).toContain(TEST_BUCKET) + expect(upload.url).toContain('image%20with%20spaces.png') + + // Verify the file can be fetched using the URL + const response = await fetch(upload.url) + expect(response.status).toBe(200) + expect(response.headers.get('Content-Type')).toBe('image/png') + }) + + it('should return direct S3 URL without encoding issues for normal filenames', async () => { + const upload = await payload.create({ + collection: mediaWithDirectAccessSlug, + data: {}, + filePath: path.resolve(dirname, '../uploads/image.png'), + }) + + expect(upload.id).toBeTruthy() + + // URL should point directly to S3 + expect(upload.url).toContain(process.env.S3_ENDPOINT) + expect(upload.url).toContain(TEST_BUCKET) + expect(upload.url).toContain('image.png') + + // Verify the file can be fetched + const response = await fetch(upload.url) + expect(response.status).toBe(200) + }) + }) + describe('R2', () => { it.todo('can upload') }) diff --git a/test/storage-s3/payload-types.ts b/test/storage-s3/payload-types.ts index 569860af076..72400185656 100644 --- a/test/storage-s3/payload-types.ts +++ b/test/storage-s3/payload-types.ts @@ -68,6 +68,7 @@ export interface Config { blocks: {}; collections: { media: Media; + 'media-with-direct-access': MediaWithDirectAccess; 'media-with-dynamic-prefix': MediaWithDynamicPrefix; 'media-with-prefix': MediaWithPrefix; 'media-with-signed-downloads': MediaWithSignedDownload; @@ -80,6 +81,7 @@ export interface Config { collectionsJoins: {}; collectionsSelect: { media: MediaSelect | MediaSelect; + 'media-with-direct-access': MediaWithDirectAccessSelect | MediaWithDirectAccessSelect; 'media-with-dynamic-prefix': MediaWithDynamicPrefixSelect | MediaWithDynamicPrefixSelect; 'media-with-prefix': MediaWithPrefixSelect | MediaWithPrefixSelect; 'media-with-signed-downloads': MediaWithSignedDownloadsSelect | MediaWithSignedDownloadsSelect; @@ -92,6 +94,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: {}; globalsSelect: {}; locale: null; @@ -158,6 +161,25 @@ export interface Media { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "media-with-direct-access". + */ +export interface MediaWithDirectAccess { + id: string; + alt?: string | null; + updatedAt: string; + createdAt: string; + url?: string | null; + thumbnailURL?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + focalX?: number | null; + focalY?: number | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "media-with-dynamic-prefix". @@ -267,6 +289,10 @@ export interface PayloadLockedDocument { relationTo: 'media'; value: string | Media; } | null) + | ({ + relationTo: 'media-with-direct-access'; + value: string | MediaWithDirectAccess; + } | null) | ({ relationTo: 'media-with-dynamic-prefix'; value: string | MediaWithDynamicPrefix; @@ -367,6 +393,24 @@ export interface MediaSelect { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "media-with-direct-access_select". + */ +export interface MediaWithDirectAccessSelect { + alt?: T; + updatedAt?: T; + createdAt?: T; + url?: T; + thumbnailURL?: T; + filename?: T; + mimeType?: T; + filesize?: T; + width?: T; + height?: T; + focalX?: T; + focalY?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "media-with-dynamic-prefix_select". diff --git a/test/storage-s3/shared.ts b/test/storage-s3/shared.ts index c42219a11b4..ee95c9b596d 100644 --- a/test/storage-s3/shared.ts +++ b/test/storage-s3/shared.ts @@ -4,3 +4,4 @@ export const mediaWithDynamicPrefixSlug = 'media-with-dynamic-prefix' export const prefix = 'test-prefix' export const mediaWithSignedDownloadsSlug = 'media-with-signed-downloads' +export const mediaWithDirectAccessSlug = 'media-with-direct-access' diff --git a/test/uploads/image with spaces.png b/test/uploads/image with spaces.png new file mode 100644 index 0000000000000000000000000000000000000000..23787ee3d712ef8026bf058907f0b8ba57b1591c GIT binary patch literal 89728 zcmeFac{J2-{5L$NkwG!YQo<-pB}sI zKp+-wwc2ElK+MN+|3lA*Pm~uVWFZh(#MVt_j^SQ^7(&H?{!R_!F^H9C%`uLvRpicC zJKUCVynY;Qk9vM;#gJHitxx=e=Q4LzoNahO!dOUP92YrWUm}G=DZe~@x`E_l!5L5Q zd=ykUsyW;mmJu?P7Euv0QU5osV@Ex)L$0d-L&R{(o_xbeS1%MAgT;{$0!a8D125(h zdYM!2gV9kAJ(Swz@vT;Ra`Z`!6XnD^-z8@D#p0MN$T6o*PM^a4n7mE2+=gvJ-*z;n$~m-} z#R!Y3`b+LAC+ee1BC!MN^hwHu&+xFfV))pz<$Ut6I3G2Ec}drNG;MeU!^R|3Cc&#b zCN!RvS!PzVelTUiqu+gr(4v8BC)Y-m?Ok%(W1>Tq-iz1H%_Q6o{|`+C_ORC#8NAyJ z2U4X|f}C|1ZZHWR9@Y%2PNWj>KYl-NbKF*)B-=fInRd&#F~jR^{C{pCjg}+j+&pbR zbJK<#+Ti}XM-+BJhTwYHvu@RLct=8-b zpZNf#<>fr3p)Ob_F^uizM*s z7|Td+N{CbJy(F0D8g(GFgSDM5-*P z#LT^DyM%3Pdq+|jv^}Nw=*>#_@Y{`2;Zf{A44ogc6j`Zd|5>VoT7VO~BX)b119>$1 z(W1wt&bs5rdb{m&mi;x&Nq;>0H^-0j^0e#>g#yS9tPkR_*l)3|d|4J8BZuYmxG^4; zMub+pkI#`}KA{ihCLP2M#M9ey*KKp16`p}D$gVmk{yv|NsCxC_^NieFlakW7xa9nN zn)Ag^gF0+=XH$3M_aPQ~&N0GLd=k@60J{ut8maJ!q3uUy3SG4m*Pgt~s-%bNT`JjR zCmHU^9)bH_3%a!L(X54}Ske%C6`iS){LKQ~nOEt)&KWx@x(ZkBjZsC$co`RR9CNeC;d;ap&aX@#!Im=$V)6C9a~_iCNdljLQ= z?^y!$6O_)Q&R(crlHq3T0@f$G{I3nCLxpE;D3N>YtP))jjoiUjrK{tes|Jc9gvgDkRu|(;PAlu* zBZU{wX2?R}K@T1tUuI3_FZIzQmpO@N2bnfYthQx-7fg4JvSi!HR>j)Qa2?~44>BbB zYpmmQh8!=I61`=jfz?InOjYtiiFq=?-dv1JO8cdE5GmOf7S~E_~&u&!`B1@ykCW0^n zkLD|D+|OJz!xAkw8sf+8&d8*hdkG?kDV0x38$}LZK$4@#fGH7nW)^()$N9t~=VRS- zO4DWz3385#VDDOi4!|)R=@yiZ0Ic)MSssj3!T0s%@vla^iV7+jeObdOy8PHf_zx;G z?yg-CanyL(EUOE-tUkHw?FBwb%u{7gYqFf`)|r;01Dt$_2At*8eCk916+NKFH}Zy4 zaCbe{Y8xKMXn4Uquc*eJ-MvqW&SD8jOY~SE`#imxqAxKE3SpmKV6_cu@DTrg1Bfw|^*_Y@MO2nJrmlr6LO>-1ojD0N(ZLaV+=A#2-Jrz;&;H%9k zRBImRC5uX-2CX1uOUi9#=F-FPla<7`E6n0A%`7tlJ~wASvE>`Va^aTy#DLJ$3&&+N z$mc~i7IA*Cq~+gxH_Zq_Xcb8F=1B<|9<@Hz$l?2nt`&bzExfzkXFd7rpP(~r(K~`# zUNhvgMZj+t6|Uun7U$G-7y~RLigxZ;+6FiFbDNu5)JiI+iS-^g%eAy3(#wHz4d%$q z$(Km(UX4Pi`sID8boElzdZNfGDgJfu!#(ccx3}=VOlG4a9oZ=?V%OHKYA8Kz9fqX; zlH+5nU#f^1>`hArODp+gq{C-Bj{Or@qkfAt64=2(l^{V0Ro{ zFvIMv%n5p;^H&=82tn`x1;ju51y#25Ex8~CZoT`9*e2cw4UcJG9oy{x{R^pU#ton* zb}}Ebl<8pue2SU4TAKC8dKjYCoayevH$WCCSj~!EpD&#~^{ST~)fg&0@=FY?! zI>H`h9Bn!y7{1SxBWF2gIF1`D^T`!J`f9?J>u=Zdl>;m&$YtC-RAVV{rC5?YiDytb zA@(yYLVd6Yq+hL@yP1C_9pRQ@4xQ1q2_zM~glu}>gu-dBD{qXLksLa03#?gh-8w^O zup4%-YA@gD2j!lfWt06>c+;nvdj&K3&`CYmFI1)bWc( z;u#?)(qk@U46m8J&7?C8@q9mj3ygs%xfx$qeJ(#lCf*gG7~=4}(g=3THVvzEzKod{ z!PvE~edKRKelKcUlyl6SJ(QY^z>#RK!eddPy$ntE2fuAyGt>px0)p=mOxEJ50`r_; z58n7eDQ9uMzaeZ@{(#fK$YmdxS%4|_0m+D}{higF8#GI2Q*X}`X!vNqNzeG<)aup2ajfi9N}^Pwr2@!H zv_YT2GJGxA41Z7Nda$dkodb$9gl=Wl)ARAYB(AJFRQihOM?@>zHe|IMt>)jBhJ!Wp zq;2l=XeEa%Dt^&ZzwWDXjoi}fu!Ix=tYF1Bl z*>wz;FjwY5dIeQq;c(J!zThw}UZ5_=LM-{%bq?F-K+j6R+?NA6?ideeyQ<8PjrM@3 z^m+7*5;w?(Td@OO;NNvpXwJ@UCNA%usq*8M6mA5&#lwb=4)Yg{6tg;3nW~GqY*dzN zD5mWzbKhlruwCpkU%Z$G;R6AIGeI`Q+(8u)zyA&Pg=hn(&#llgUNAmHk5O6^zJ|Xk zIxQD$v61L@o~Hsj6j}tn%99cN1@(LzSmOY_xW}E7$^5L&M_p%p<46Om{S2tK&pu>gw#l)5hFjx! z+u@i<&^Ra~jJazYpKsx6`B;PP(pS%XXFCD&}eSw~;cfIN{pWal^)yBPzs=z+(q5u!( zC{??um^>(qX-KD4Q-lcGfs6S9DAWM@8BK4~rs;3Uq(xC{0@sDQ!WV9iI@7mnrsR zpJNTl>m_mHAvLmheve~?^o&u`N&zkFJ-r+GA(@u!$SIa7bLy;^MI#)Ry9*zT&^hiP zR0jKs0-r6C#h&bUejJ(U)cA`##mKStO7Mx12LT}fvMP!X+^fgXFQ#W27GP+0CnY1bNEVeiB^NR+cb5! zx=70%j^GyFu>#00DIJ8X_qKg}C!K=IbFL^R>Q4b}@NF8ElIlDeH=8t;0uSq*>>BwO z*OCqH(um+S#(f_EW@vlU}@DfM$>_5d%Y7yXic zK7x<71Yu|63{GQymmHVyxULFhzaoxh16%Rl}FY_{f^YuPiG%}Q(J1rtx z)PyJdhVR3RoB1T5K0s#lqvf|k%Cx3qgZCr#^P=;KqwCy1nZy1Kg|s$j{amjHf%6;r z*6~sX99UWOZ9c-;BJHw!5{`3s_~6LgO0P-pJS#H`#ayJ>86?F2AgzQJMXAa7N0H%* zh`iNj3CZ>ZhKq&M1|$F%n7{gZ68{25WPeBP?ABDS*G9iv)+a=NzY!B9;~vjPg8kr6 zuia=6;NR(yaO6IA#(sCkGwzl;!jZ?=#wo*%sOF@bg zbJ9^i+iP9d&ebz9WbiK#obPr&Gaik!Wk_*qW%z~VhEp^}db3sK_=lrjO2YnBuiJc& zVT+#fPzyqJ1WOb)ukHOPoTewoM zGmS8nna#rufR^?z)_3{r+R99zuj2-%Bw7jDc5=Z4JH+te2|jPo9tGe@1TX#Li5JK8 z5KQ-s8Y$VrWWo*&d9+8AW`cgywHev|Px1>jgTJy4HmfBWbA{{a!}0Ccz7eqq$%P-T zJTS%FI;V!}zR6i}bZq3-S#I?s6$7;<0_CmV zgF5azDB}bmK)}+31ft&&Z>qngujmC5~^DVg{4|sIcUpr*_4n7OW zogGhPo%H3Gd+Y>8`m950=LG$9$EIc%ZJIuT{6CeHyiK^}5%F{8+N<37>!rj<3hQ8d ztcE?GCxw7lg-(Pba}H&RQx!*|7VjV={4!e%9;zH+<>v`wM<|FZXcbYwXD&-=X^ zJ7K$XEBkKI2?>i!@AI$P1;*$a7PSu`hbxeCntgxi6)(4&4Z?OV6*MX8XpV`EFkc_$ zgBM&}aKN0W{d&s5b*$l4rul)lTP~{Le0<17PWt)LG0dg0d||oVBb_2%*>`2pl(?}4 zNPu~94>Lu3uExorqHlBFX{xNUzY+_?653!GoD4D@I6A?K3xPZfR}f))${tG;4O z;|WYeuriPHOZu0pDwlp&razUySWDuro`RGPZhG7*9UM7*qE8pHu6B<$HRxd|dg=oE zkTE+d2%(K{1}=(ClZ^9`1A*>z|48Qep`E6iex-&R0ra$!OT0!QO9gCv9u1ucfE<^`xJ9^g{FT zo3xmG&bZTlHE`%3+?kh#A}*OHUob&XS8Z zDG(**;Tgpo=d$>fy%od5M;^T3HHM0V$(`Td5b)YLUOOu8bE?;s7q1;3cskhI>yB3{ z9v!V7Tl?&!>>Kqd<)v-+SrR+;Ng`$<4EiM++^}M%0#6PUv2FV>LShJB?CkBV9h9fn z5t50#C^K2D?<+mu(JnvTp<-ldx_|H$Rwn(3&8*1p|8LzGDiZ%tgGqOs(*+IS!DZCg3@}*2d*!EgV>V$0-qW^Qqh#;EIg$7k&Ig*ED zhPV_r&(@@rITqz-y8GDH_Vn?RiVt`n;+C2{)Qp_yJJ-{@);#N?lx0YmRB%T8h%?Qi z;6h|w$mVqCaZZo>tvXE|ZblXS5i~@|Q}L+;REq{N14d3^)E=*jj!az@yD5vm(M`zW2y0IXB}z*iQ$+9hy3f z((heIhX+l1U9K8TC{PHE#_RT;X*ZldWkL-PX@e~V-i-`=$dc3NCb~asezosGo#K`$ zDq|(FI(KQ!PQy)%^zV6e-Ba((KTeaf5t2&pCuJ+vcnu~i_FFo)c`^n+CqG0^TV=2a zSs!mljV>h~X8&@CeCf{R>we&?@0NqgNYr-a;C9v{YHdzy_oCimnQ3ie2B0#VcZ`j) z;^q?z{x$BMuyejv8OSN2>*K#>bYbgxA=ShgT85LU*Z2YUVG|(5#T?iwysrjZ5J>J^ zR&7kJrJ7K#_tbRr3TCU9>llA+zfjiUQ-1WCg;>btu+}K~A9bhBxbS$YfFw|(j}6B! zw#&|R-+zp&zA~V`t}dF^Bpf?|?(5|3HZHo1hhN{3bp-tOwj<%3@0N;Pq`JTdnS_@k z$M)rvp1I0Jn0n>D8oC8lDSIMXVdZORFj#EACXqVYgQJN z(`p^P9mn4f#3>G({+g}m#fW+JTW~r{eJPt#naw%P+C|Su%t%-OvCAT^Z_17}K%dhN zzQk&C67Spbw?BU6JT3#}@X)PmqW7`u*Ll)+JLgvV4hO8``d=nIuNzQ?FN&@hr6ec;Ez^BdK{6Uf^9%KOCDe{su@+(H&a21(TAddLp#KCiO;AI^sX`)E5s07HTT zNJ}`ejB}jPo!825Mg{92>-0@Cy=_PGg`_?eBL9uBe50iHx^GU_&B zD(nl3Qf*+?+<+M#;kW zJ}P;qYC9$Wmokv#KBc?YY_}LRB2%3p|J}};hLE#nic`v*VhkL=99P9LU0_fm^#qNG z%8XaDqh=CF{F?6`;g%OCYHLMej&7anud^;8*l%cl+E=;Gc4BCpv> zl?k_C_tPElH}3sF=eR&*@Z!alCYE4kjDRVHSVs36NF?KN>)_tP(f6O! z`RUs!X-H5>4DFj@sj)QS04LahdL?=IH*&ajJbu{kj{36b>GiwF$&UK@TFnJdW$df0 z*`HZz?pFAODfsfaha_b86qO17vv#;FLk{J3gCFHRbSt7+_C`AlvbwfA9G(6m8|m$6 z9LaXI4wekx!H(h;smQk=;yrF#v~2R{tw)%R?nkKNtu6AB1Q)yR&;uMX~F5Ehr$ zoejARBLeW%hO@Ng)Y=B?hXZ4lB?Iszm?|;lw6IasxwhN9>!4)i*2TYAass1j8`d8Wpnj6Uz2c&0|Vc{S`i;A zTJFm(_v1A40t-2BW^Gte6|s3F`xP`8^4uyY#AMNtb463vgGmaFzO$?o)T#|Fn9W;A zPy{l@F$)AUeWPsK#zt;di#Z&bx+;k#h_)54p13F)UR9K5$rPe!d)RGQJ8i$IvLm^E zoc+Cn0o)p+*beZqi1=kHNFz`Hl#(|io>z7&SS3(Y<>q9lz2aKp{q#d-8GZYw*nnex z6ijzy6cM{_39T|gx^vqIyXikSo~2b&wdGV@4)JKsl1x#&e(VJ6eHO7uKX)69I#Q|r z`I>9~O`8~0gKrX!1w{&3P5MBAQ><`3vbmU+jBk5%XkO>E{pdnM)-zVDtEQF(Ln*gP zhqK$d&+{(00x6!SsApa9U8O)8>>}6EEgeP|DmhnJ-CIQ5_|=wdlt~rmmP18dYW*rM z%;f7Da>H5Bl!c<@*`*HbKMUopZqS~BLM`>!ih6vAJe(7qMf`f+$Z9$}&T(S?qQ`%| zo>snHHTW&-WEL??e`*5(yzfV7nzs8H- z?8#qy(kJ^1HKMZgb6lCL=#ORd9{p1JIaSO=>8#cTA%(;4{G8_%^iL37Vj`^UUi-o(lRRUJmpfSJYS)h+;vYkjh2Ns z)%Ey-(Iwv08F28^S^Y9a(fgI*h*9I$?T?6jZu1Baf&7<=_uc2K^D)qHu-w6WR71 zFUK3UYKVn$=wJV1a=+C4qOPmt?;N+dr(|^g>hQE8JrJyXz!Be*g(V`}MMlUGElp=4 zBgxIqwfFNjM6X)Ql{VOK-X`eQM(kV`EJ!xZZN0(QaU!|1St;y(`Xi35sudH#Rm6f7 z=1sA*P>L*ma<^2Y^>ma>gsHTxdX2buob$Yjxtg&Y*GT@Di16b>A}m&FhMAkf6I*0W2#Yh*K_* zN>Pm7z~HddHt{^!HfS_frYVv-H!}~D586e}n<~3QM(2Rk&V^pqE(ceet29G^}a4!ylDU3DcP3~-Lt0FGqWz#;7kkKYB0iCLqcR|xHHYGf9B8O4D@DPo8Zv0mmV8cG;JR1ov~t+=FURc$O!0Knt1S2>KNvjRTldp+ z?Xe=-!|5^;f(%33#?S%y1-+GPwe@cxv`ux?rsR=%RYq#{3dgbc~w(C5`ad$$Uy5UdD^a^tAg%SnYbyv!mGp zjq9GeUB!iVvGn;42}POQ5w%~RzZ?PpiWjE6Gou+!yLjj0s2MMQKVgd zk1f9%x+4mDIVvCl<}SLd6mKEgvC4&U9tFX!HiUOWnRpeLz`4cI1rV7w$s4pi6uV3_ zrU)`I*M!WoHJp!na5KwrJtXb!02GhdkC#AL4!suxo=TFSI>%{b9$n8Bcqy%a7f*); zz%@Y=*b2sH9s$4^y4z7DQcyi^#tV6l83zaD=d{M7$r|XfgY2G}b;f`NhTeOT2Q)Cz%5=pR3X<1>V>Gm|wUM}=?!h<#+?ra& zL<5*+3VBCJ6vwbv{AZ`=%2Itu-#>5%l>(OLn)^r=A7n=a?el@TnJEaXK}Wi?b&sGO z>%79z)9MM~vIMd&*CC4#&-qo*ZN^-{HAciINsywcSJZrd6O^_F$(5KGnUzfGRL+{Y z`5jdBW6sj`D6|K6;P#%p8=0mOTnz&_fGtu)M|) z(;8Cn@wcp6D+o^yg61Xv>Zk*i9m!;M&Flck3odkJpc``@MV71a)7+ySL}mJKYYV=v zPlO@V8VK|o6i`~8Oh3Akb8mE~jVn(GE+sTs$3&N737?Hzneo&(Gya5x2UNX!Dg_5* z?16r6SKvkSKNW7G=WZ;w0toa%Bt zOZx?E({ny7T#MB){y2EY*X1j(_eA5MCQ3`q*uU8K)b2Q-J?;=gL%SWyzw+_~0i<1S zPXZZ+!62tE2{+2%8bUG0n?9&x!%M12a8Hwm#9s$ne;ZS!ibL3g^nI$zJQUX=7j@?u zSM1K4=aNio0@$hd+V$_fW?wGdxi$*Z#VZd{B~#KT`14Hr^mb&9xGQJ*#D*86@by3OP zcUL>`6mkK`!EW+%ZGtcM;F)dU2m&7dxoEPS%nkas_`CAv7aFdTntcMPtqz4sPU8bZ zpRdAH33vP8`7ofE9yPzq<@gL6Gj7qAQ)-Q>*{gYU23Rt)C_+K%p4aeD+p?Q#jC0pY zAWe5f^>2>+UM%?narPY}zRy*)$L zEwt>M z*NuKwD9kICpwq}Se`;8E%lxhdI+_m@fQardZkf;!fQ;}%kf8?8amveZTch$HVnnk| z^Gn~$NM2b!Ed`x2S~tbFHhPf|w47iycU&W0IMSId9k1}7%)7!9QQLV*2QlBDn2?Ri zoQFAQS1q3wVFI$vD~fHX*mg^JfjW#Td%Q+PB9K)@W!}RAvCB|AWfer$Qi7_EZ@k-Q zCm1bj{ksX8sZ`WnhI(8mp@w$rSHo*Z5Z4XY-DJFWT~ibML)IjwrK- z?ofZ_VgTQv=kF_|gNYd)agDfb!D6F)pC&=ux)bL!HNc6mK(Is|g~<4t&`C{?K?V5rM_ z3_NF^hAMwpMrc`IEUQvTGF}I&eQ<%N$yOvG6@WTjdZ_pcwOc$S?2<@{{t({AsFm+} z?H6&acR`8~tO{sYh$h#G+KOKze(P-OxiPJ5 z2(qZmNH&WsJGN5EK!t4SG;Dg8^qd!0!9ekTx(z=0N-X*vcV>JZMb#N*Xs&)2;)eb_ zmRU%Q{AMMKtI8enNTSs^Rt3*yW-x>=8tKKZmYrCWFkFTO&ywc3wW}4x0@du8p*Bxkel|$M26cA50(ktz3AG+)BRC&RtL3ADIgZfgRlD4I^#5Fn8z(3^NSrzEAn8*$a6VwXU07jmd_9&HA?JJ{eYOyYv z%uL$Z`4H7!B}eFRB57q;vf3zPcIp4tls%fq-$kqM8Ec;Q*d7xzAO5ow+Fs0FN?7qo z;wY~Lg!93ZH$Yv*P^m6=M^=PCKLJ9C?S#C!Yw2#E-OGYkz`C;f?n=m;L;XS3q1;O20!%EE&9)Go8;)O=fZE{`-xOzYt!q8o(mB zKeqBTEs)Zod01s;mdfKgZ8E3Fy<+6^)yA=`EcXnPywcaR4?!$PM_RGlwxAu)p*~nZ z;JNXOLWl}X1DWdE({}T^i+bEN`Ylmo=r# zla$*8W}0L!{I>;Vl23eIqQD?eqa$~muP=r5ms(X>oJi<#sME}kzR!t$zfWry&$}EU z*XBm=9aMR4=c5I}DcPG_CPU88uRN&v`V~KEx=d4YuG0<~`<(f(vTtv1p?q}t*OM_{ zcsUmgerxqTp%0#}9H@&jRL={?;>k5JH7N`q}KZL zWzKD`j6rkL-{X8&F;6<&jlD)_NooN)jq6)Wl5q$jt-dyjxJjSfN#1}Hrg#S#dP|kW zmnWlxKMuE*T(9gulxo&4%b#Rs0`*PwIHod=2~!9dqZ72($SP;X0{-KXP@b*B?&WNG z?m#KZU0p+U9L}q}%_+F@Q%zx7I3y^0Xj6jDfE?ywB1p6s=&?hgcjEuutmT{Dd`am4 z&jStpDz<2N=PfV7@PZ;Cr`~npS~Ela9@n7zA@ALoIyQ+aT*Z{fy62Xc+wuDY(@I^B z?GuN`V=VEtIjtM4?45Ia9HZRWhv>ROXWUcxOtFy;-^|w53YExEFTjJUJi+6=d{z6d z`*AeQXM*l}cnXWy(o_2g#^B{(riJ@>?=Uqe*r#8ZKfzrPOQVi2eT;gv=NuI8*82T? zUU8Y$Md?}{s#C*HbeGDJJAhJ~?dLFsvKTf^m^Z+V>cmrQ|wtiLXKQI!0Mn^4+p^UsAxbad5Jvuq@x zkXu@nDGNzYkRxNsRMInc2Zn=9DPFGQPP&ZkM>v09vfk4Nw_WVijS6Y+ruaL4&2K$6 zJRE`V^<*TebDhW79nwVgmIm36F%43d!o@HBy)gz`Xs>tqV+^4G`dqA0mRp5!;nn~q z=yy)@MGgRDhMQb7kHxfMnagCQ?YqNelY?-sVw(DR+hy#6Lxa0|hQ8;A!$y8zQEMhykCtkE8|o0>Ni=(rVHl z3}0)`i~Kg#a~qNRT>rnl=0}o%8)Ykh7N9|D6uATw!N&z0z|we)$HVqK>ZDxJ(U2`Y zOM25v>lNK-uh$&;hpK{N{43)oFA7#dr6Ht%KHDkhX9mZ&{H*Vf;yFa1__=P912XYB&P$}efLRsF#o|dNfi%a~= zLs)JR2L#k>KK_&%Lju5wV#SZ57ryclbjNxugyY3{B`Hk9ebU69J10$*1IOcx4_zkt zmk$Y&_n^|27S5l3v@j`3VBu-w2ii9U9?ZZeJf!?F=AEihPbnwykiWj~kG%d5+5X+P z1k;vUB-{0gLIAazw6Q^XJ@$lj06AC}jyK|$H6Y34B%YUq3U1z$5 z#iSJeOd^8ph3rwP*xP0Db^K0HFA?9PK(O19Sh^LVvwxny6$R}YKq zddRH^%`BNptK?L%h{dWI5uUx_A;XrT^8}YBkVmd+DPs{UKV^PgCWyV&GW%v+Zg@df zhs_VoZ9d1AIc))Rm@}d|Y?(vFIcG8FL+3(^xu9q+D4Gk3=7OTRgp2pWfVot0E`y#c zEbt!EpGy_z%20C!wEth~ieo9|SNXF5a|O(~lGI#DYOW+TSCX15N&PP+DL3J=^lCTL~Fm-?!Wh>QA-n~O9K+aU;sL7@Yh%#V(*8_Cg~|SopRg< z$d)7hafN{qV{I{P=(YJD5vbQ#2_CJnuxE2bP4kTgq!YLw$_!mu=V^{*_h4 zh=yKcBAT z=L_2v2+OS!ui4SQrQ~NF{es6KKG%nw$`Z!y|9#t-|8^lX=C?*4+H_(xusJ&9&c0ae zd8~T)ImF)MYDXK6hm|YrFg`3M5Vt46q-nFMfPj^0GsRAZt>oB6LXLu0Iz zKWdC&j^8~%IJ*pmUD=eBhwcrpd$P&Q6?A^}jUASFIJo}9IjRj}?T6Mkvv*%BIw%G_ zyH=*;oQhESQ2N=rwI9#A>Sh6Yz9T4JdJ%@SD8Q}bq9FDL*?8s`(@8ipuBnWqD#dKw z(LG_9gZ&-*7LAkCQ#IS#+OKxtxa46FwBhJ&%0}S%#)?<=XAmkj>Rh-6|->XpAPv3Rx|0Wb|$#68p(Z0!%f?nIhdi!pXm3V~YvjE=9*SSqO zRn(S~O6EzD?Vs*h30TS24~Vl9iXue=ZzhwfKiSlW_)1_%?>@giI*K7Zel(~uo1$Ie zs%U#g1!vm{{clyM#VsV}PeJTc=H{z#u+^Q*i?x}-&r{tWTqPmy;;WWXq)D4rxbxq} zjU(ZL$g98AgsCc9^&C6sdINFy-mi_d0|{a2UQJu~2*ll4bH8SrIu>y)?_QC<3Zi7& zZ-H4}TZ@hvwoUx1`8_$XCvgR8r7@l$tBp98>X$7}tSNIW3mlRXh-;V9%<$ZaLpvuW} zVlU~{7tUHnq%!EIV$9!m?d@8ssI9FxQ-2EMf{@!ep}pbifjNN;*SVi9{Eo@(O%9wH!vHj2WPSBa$?Vr^JVe$NM^R_ftO{R&d`nyC1|zDyG0 zhZ-~1Tb9JNaQ+*n;SI%DF5#1Z=-!TwuVRGlA0JZRCko(oFkazUO|$u@b(xET4Kf3$ z+jK!u*FR7Du@jlJb;&{bS*BHD?kh$|wxwhC=IxXvy`$IS%K%QU-0iSc2RQj^FYmV+ z;AFvur|l@L)cQ{{|AT3NE63j_QYL@aL`Rq>9oyoCSZk;4-t*k3_3HI>-77%5lTl#i z3DA^ze*KmrxU>2@{>`2&BWhYna7M4K`3)5R-qYn7UeoOM zSnSoeclU-bznr_%9+o!hZ59G2gM1LbS{1SK^NM}{W9i7A=ECuR@ixL{eha7U^frZ^ zpl{u@;U~b|VNHkN0&vfA<+Q`dB;+>xWi#$s;9HI5IxOnnY5(7Gf&ip-TJUI8Q~ip7 z#~{nndG)ng;FMc$jc`!d{$F_Bi>pB+KH4+Y!Kb&wsV}dJ-(b3$CoS2wi1g*R!;vek z{afPQ^Usm0cV;??D1cXAjLHai6|nmLYsLBLk`Qo~CW}n$YxgY*99?*q%dG+NQwWuq z#4V1$6?)O3{#OCstsif_Fc08;UjHR6O~lqFxqY+nj)`7>O+eX7>Sd6)1nI~f&2gXJ zaGN5#eq%7Z^wM-=P{F;YvMw zy|w>W?*$PdVS}Y7n40cea0vTMr(GvSaL?{*^53utW`71WV#yuMkL&Ke1YsOe^lM~g zSh?$YyNr<6iF5@&U;@emtUKi644t0>hgOB2LCCoLcRXFN5HBw zeeeBOMy(4xcUV}%`hD(;u2|s^7w<3LYAr!hIT*Y4f7qUA<@h7#XNeJa2GC{`6bR{l zRMdSH4gp>_7~xxu!kq($UhG=)rF?#|ICM z4`w5i>|WH5l!ul34>oFPqYakIevI6=Qb6F9eRs6~BVY>jVSKTp&7NF^W5nm0+-(`zvzMsT)x=wgtZiD!SN#Q?=(-}AFwj|TT#_N z<+0yJtIU%sE4__95d&8~UY{%j0=U5wXiF<@-~yNXHbs*^fBlar3}+(n%`(6)7W<&J zmMV;U+34%lXw>?Sv9oyx1R*P`UWlU6IFa=$i#G{a=@kFuo%s_r@dkKY^Ydt6br_20 zBAOKlTXF)XV1Xq#|Av)Y)P(R}ly@E8HB@?$5ZE825Es_KdX7@jI{f1CtXyyMYv zYiSb7%$@hfdzbCZh>`xN_Qc6y(~7j?3uBh`!G^!$CI{N3o(yG3AAhWG9B~_=QeXDQ z4}zA?%Nwe}9D)yv%1Ch`$^}<~OoE>`<%#sI@Sp0$UPM(yb79PW!-ewEmbj7r1p5}> zSnQ#CWRgLbwZ^d;_iT5+g%B;8muTX5fK3z}ykR3V1(hQiO%N6@%5i@UQj$~ci?GxT zU_3@zLcDf7<}2h10ZlAvJ#)U=FMd$0D=rv|T~n=$ICChk@N8H)eM4re4oLo7llf*4 z+-CW&4*~?NEL(0T9u-*GWUx;Pt7A)3*ee(H=46$KX{GFVBB6Px_FfD5_HDuFPXOxH zBNCdEtwgRF_e8!KZ=X`;QNRD4GB*x-2Md5|>sgU-dj!IgUfw*ZG#msBjh}1)dLzG$ zuNtoe`>x#eTq+hDb%kNd;ozf6+nk+@vU++zybw7rf-rp%!6$A&5Ua2w-t@EJ-SBx= z>`1s`l983cu{VOI3&F*GS7H=)ds~$(-^`W?k5x*H8DcpPd%gObibk7V*Qty=J!)y% z{Kjr*lyZ3ZORE#@+wV7B-=shZ)eh`#*F@u%oY>xHAe$t7{eURM@FK-0Vh?9|{P6=y z*G;|xN_W4xv67NZ>bsL1(AFVh#u+J%89bCb;aHVV3EMHw0K^Y^thn(EK;XqKdM&3A zca?vsBpw#HcK1S|83~sHq{@Z9IoWecsZF141PGjL-?L+9u3&UO*x0wKu>+d&e>W;y zMfeUU4rQ*}_^Fq=xb%RyCv2;gqqyM$YEDOx0SZqt_5;1^ zti`W80=)lcppe&65};kS$#ynfeU(iu>GDgEK^^(d_DH?@iDqOYF6f1-;- zm7Z$S3edO8Y5BHMT<|YSKs!J_Pej$=viA8kd|)0X{Wa^B-S5ak)BdCl*~wpHct@5!rRNCq1O_5T|{LKrM~ee9czAXe$PX5S%M_$weD zgSU3&dkVLF!y}!QN_T z1lgO@T{VV@&M}lXPpTd5ndmQR6lv=l^*gE6+^!0~OEOhk6M_xb`;CMkC&Yl-7jvZ$ z0r;yBej->3%w6r=N~MdcW8ut=(KV(MhO2?zo&V}K3!5GuR;O%Ge&zeQM=9f2?!dvS ze0=BQsOZ&@+1vgSjfZ$m#(zY5` zwWbRO8N$UUB7Zr3t6N;1*n#=c3kWjoNbGcAtU`ukB=FH3vzGl zlgaJKf;e9MTg~lxeJ=`6V!dlmB7XSakv9D{Oh4;c)KLVs4j%l#E^z42-kUa*BA(l# zaqqanTMy9L^7rjvx5&4e5cGf%1c62C1hib@`}RD|^lo^F`LT2x;_$BfG9zc(oJH3+ z%H%^t^|d9^Ujg>oP!S!Lg-i;&SN|_f6#goNUwml-Eq{Dy>G);qsSU#bIC{^$bU!lA zy|{0FbmQ&OqV8GUAe z3&LN`S^~%-!4|V1DX|#bi@tV4)W0&IG%QXd&xw{X+MQ7$8J$BPHYyvh0{jaEwmdZw zzcyIbqjX7c=vU!bWvTG*uD_76{~fCT&;-cbWbk2dk-#fkM!+Lk*(AM$baN7I12FeV zgs0(HxR_b=DB!YJH~wcIKJ4m>y;?x6zIE-q#ts;WIF# z)9v=nyMj3~#036}SD99LCj3}ed+%WxSnKQhADr{QW zb9=Pr>lTgZXT4PEvY=W5>_b@d@8dJr=VWS3L8!og-g*$J#uOX4=6uzzc2V@kIBZM@ zkQXiU<28#1o*ml?wVONDv18%2_2ccvS#*=1!*oA|qP8M1&!X(e;GH0@+viOi3;$Qq z%lCILt_EXo+e(a8G}RdU9lx=$?xa$$z9V9wl5U+bIO=yVsJY7$q+{t}QhpPp^E5N& z!9Ji4ij&-!u0<+XsH8)7y!+a;s>5Kv>HovtTgFAXuI3YKdcY4 zesbT}eO+gt$9Y_5Uf*$4uFH?S*q$a|mwz;k9P}y6U^uD9kSK=Hh3wa;Eb8_D1G)71 zm7^Eixm2rFjoKs>@T<}p7t6}m&OQ;kw2e*94;ghzecxn;Tpym>vOjL)K9W`_B*fw-ryL7BRq@t|`UT0u-Ma^Moq0${ig@w@W z$S+iDeNqow$wI0V8-As1^;TUD6LjQSl~~e29BcaO9l324HKSc-j7kTS=86}AtyRtw zX|}6-SC8d{q-PE|Yvt9Y{qf@+5t<4e>j^Lx@b=(H$;&szuLOBM+UH$xVlqd217a4i z&bI>RtLsp;mb!TKW@48- zBghzCQzt<=IT}ox=(fR1yWZup@|m^F3Uj12tDbaFZ5AALhuKJUDq@5{x<4#dKBfmb zjJ%i~FV9vmD{E_R3mLxG2Dhi#LiwtWDbn{09p64U;lWf?^P|x%B}dadDsPP4?}{*O zt)iFj{n#f7N7nK%8;)vC$O*S^eoz+9P&WrHa!{x@KckBM(2IxVxOTu4#v-GKF=}6z zUwSBzx1rn2cU0QU%kiuZ2mQt|heB;GddLY|tWf#r$q=m2@vBM*H&(b+*%|1lctBMyn43DjS=2TZd znpZ21z4?dPo$n&K-yu%CjO|}O25EE9N0w&($01>VojSx&dCyA99EM5wt=+jYqd!Ye z4hAw(u7|e`?r!Xe%8o`U@p|b?XEuJ)WI>T zctK5qO@){9gsxQBRLx3JMmJ{Ra%7+*&Is9J?TQ~UJ$ENNv~(!c+B-_8s2)cy+dbWR zu^H(rTk?>E=~Vs558;d7)rn?ye`Z~auy(eRpC>;f$;AsB*ozH3$<%n{ zdcO-9=r%#|(K8moOpOZ;$-75$o|G)>KMgrNP$VRa61z-!+9lN5)_oW9Oybu3@>(X8 zkwWhX&u&@0hF@jx(45j;gMmaEHSD?jZ__AO;UHgaeI+*X zMo8enVSnmaHnDR_*tsuWQ9*)!RPp!v@(V}L*gRrtJaxHVjAeb5aXJm*t7{NivIxuS z3#yX)g#{q^YuNuJvsv26M_X!=Co1`j{RLKnA`P5sB23x$HS6RAq0FyVe;$*l&U$f< zVYd6{mH7dXz>VMJjZlQpd%Rce0T-)MRZqr`ZBnWOl6+QR1ILV!+1q&}sTcEZ8d_$1v7C`zJyU1V*Xjd(Ww)vEqrG{hc6W_m>+MbH!z)oMjSBzV;w8~i_k2%p_H6~$5PuNvI zxckPA#}aqYxqBwXwGC3ZwIqnrh=#`s@x7c1v^Vqb<1+HE#4@cecSYPe+$nt+dfPs! zx0&_58_b3-#|C#$huyB+TbLWG6>h4&c@T~0jNL0!vK%8<>C-QtorVu9x+ z#pv$g!}G3ek(AvySy(&Hw)HE=VLWdO;&(?#^iCqW27Z9FwrK z+hTw`Rnybz5rPlBRE^`D2tGJNf}T>?G!srsF3x91)OHQ+4;gHpdpjQkL2*~R21n0o z+lm3R8G^l&?FHfKF-LEWkY5B=DmzXTRE6sn4|}fMR-Ms|#r4VS)$WI_ubnPwvX68n zPUe)>3ATBaq<8$Zojb5Nw|9Qj()I+;<+7AvCziZOR8SgXG=?sxuC9@Dm?)@;m?Jpi zxl+9^nf>z@w zt2gw8)A@To7u|9Nc(JyG-;eHN${JO=9mdm?V)TB}@HE=ct9M+ge5;S{v{0a-GOFdR zx))FTWGp>8RQdGnYBzrx>bTvX_Ko?<^0q91Tbo<$o63z0h3Mjpcqac{7ss7Vn0Gna zUp}9pyDGhW3}ipug>b#GH7V`6HoLOABIY!x2hL#>S*9>GVi=ouw+`;UmgMvn2D#Db zA+d9sOI>{$DKz#F0h9aOlcl@Giimp|+=xewcTY4(P=?_lnbTIU?rF_M!h@=>c7cD6 z!sz2t>%l-b<@1lfbw+a>wz`I%$+i^jFFr5^s%;CkI91QBkd50e9HeTkHHWqocCWzQ zMu3s^V@2U3G4TSkOq&X7R+>y*{^m6Q+(o00%RB}HLp)nelWPpK{grc{qV%2O#KnVt z21QNSXv?HA&6up@`B>n4b8H`U)mugErFWy08-g<9=Kv9pNfXmc9}NqPg^77w;XW9c zk=?pCy~a@4NjVc0dEE@pb3AaqNbil+NqSEYur=bTG-F?q4`Bg6R>+Lrw5(LLX`16Z znu6YI(+9hW(=6Luuf3F7;YUpl$Qz4bwLb=T|6TjTNui8Aa(P@n%5Qh@;m5W7sf8Dr zjkB^vd^zX}{EE!YbsA$OnO;Sm2LeThJc~CLFMovk>%(Ia+K%WsIlht~ImQO}=(MDQ zJyPPC2A=Z(&uLBJqCZ?PXdF61&lwA*c@5Rdya+VT(qil#TBcD^MQ1gH@VLKg2sz1C zu}AVh&4)*e!Q%o`4ThGrr`1${)8*)y)HP|_*jlz|L>EoXNzD8W+1Ba&xv@r;ZY8^5 z0e7`0-I|T#o&ER^stie{I&XGkrnjSNzb2XTP{@A9@RtEBPi$~eD6=M)SYAU#A)}sE zb3XPW^VLQ_szY+wnE5kCO8Lba!x%~Bqw7#R&bU#&(;RYW{+Uxunsn>#*^8;QTwm(K4@@&ybxnMz2n2GA!W+286?ph9ql8}AQjlQJoPZOQ~QG#>HLfYt_$S)Ns>0VC@TXmdU28*SQR5Gu5zlG~weV%63et!N7!=R-?2UL(`MWSqaeQba%@@ zX!EAUrA8Y`deLTciZdpA>pr`1HQx4}vxoTgek1AEcG==qp=c35trd2VdAZqF?# zco3-y+d?WbM3p?Fh6r-d=J{jKSDE5hk1o<|>x!n?J=JqL)T$kNWXN*d9Q2a59AQKBkJs1Uh#PUQegdNXw>C6i{GOh}RyIVk;b2+YBP?W^jmhk zH+LiPwmMo<6U@wK8pwHm?To&jVG~P*GoT(H?()T9vWJfUaRZH?gNn7}g9Hes>lUQp z=)M}dJSDxU$(V8k2l2k>L#zAo|1{HXSoesxA>)o6-(&c<$JNiB`!l_g5^pzeMftTz z+ucGIh1|xzI8H=Z{Hyw#Zcu2e*`!A^xC{KWlci9|MG3#MUeLF)x7UU&2<;NgEQvkx zpJrC+pYR=aKRGE+pyp2;WuNW%53`H%F0}pDxN-Tshd8~jnr9fw%wNNNFURz}p1$5v z1RpW8G1Zj~_RMDyd+=fs=XAxm+uZmebD89`3vqgTxj4n*X!BM|0u(&KNm56-gL=~K zaugo|IH!&BQ3xA$weQ@njwif$I8$LONhytuGuVY~>o)fc0;p!iWE8d{&Wj_W=$ynKDcQ!vUVMh|g#l(USpH_A># zJkL&hBeLS|2H_yKpEo2`?@K!!s^H4cf``m zqG}Aoj}5nBAM*9uQ_8sU2<~H7y*87SPM%V<{>0uu4vEDhh>h6J1g`3%fw(;yf5$cK zsyZ{go>nju?=U?ND{w48D!AoTUb;8wm0ug=`k&OwMFrv*@gtKmg2Z5CdXIEVhN1;}Fo7WaP6Lj@Tv?KRIv1qK7JXL@D15M~LC9rI}RTUALX z&f2sna;iSG?R@Yd-P`0~FZ5AJ$X<CB(`OgtYerJw**@f1Sg1Nuft_tvoe?~= zV-V?`9en50@#E@3PF_vP+Sykg%~J=gZRZ;ge8#X_$YG5R>fUviqi5&Fp6K7W@+?fl zrVl%}ZG&len=(@#n2T%l#_tL=nTq?1$rL^$iVc>RcqI+#yOsywBQB{Nsq$xP0G}6w zwo&}JfeyMclD3z=>cQLTC5i8zLk`;2uBm&0TN7C~!e4b9$S~5NH>Lc7#Q-W4wVPgl zTSb`3lpVRT5HbTzU}ylinGG1+%mX^vk4chF?xzKQkd^$Z?o&7f5Cgs`L)Y_T&f_OH z&{{RfePRI1lI-Bwiau>@>?2|1fn2L~n#G|}yiI!NIaIeL%SG-H4&ps>o|m@tG8C%% z2$x#Vz?Q?qF!96gE42JOsELjV?JA==mH?UZL#Fsw78+#W6Efm%Fdma49hn&do#e0n z#Tz+!Z|*^z#>K&(Mr`ChABRb|)&6kx?w_lx5wM?VPpHUP-d3#I7kJ9vFtCEcL8??jU4_abw zf3F!cqP}>DYhF}|I`I?-@pR%zbf(wS^5I_3f6pvPz}wD?vTJX{7qp3nq^b-CvQTmO zg1t@?I}TXWi`Kv)GLnKo({@-2egn!`52Je`z>QBeAKjlw(_g*TtsS00+f%Q)2h zD#I!5FE)*6Vfkp`{D^=L-pR>b(dHw217E1(99mqQH@Dk|CP4WHw2N(Ufbdf7A>PdV zm8oU9=#8|ArsTeZ8XR6{X0i#5Hq8k7w}+&LX-_w+w2<-32DPjs5W)|OUs5G0oYJZL z7s4>#KeA-sIcEO%Y4&jlKVg;vUe4rA`}?ZS-BQ~eUf|Pqc_G$1{^3LF2uIp~T*!4w z_4h+~6f)_lvUF>LbnetBRz2SQSq!q5>^!C4`&0xkHP$61n( zKfB52AIEZd4*{9`N4j^{OTR+`_7er)u6M6Q*&=6#tR{j4Nt+7^Um?R^lNM@=lY>^o zXzHKg)(kON>__rhh#lBGzkkau^`O;39+8ls2d*l`CGIq@LmeN}%13kNAGK?2 zfRpc;E@PJlr{c=}RS?yu(kpfB>E1K#e8?QUi_!Z+Zfti=j&gF^8;!TngttkSW$IP* z8#ZIjug7wfgekKr3uZ^C)tac14yq4;C~A4Uuss_KS~>*GNyGA3*>EA>T|m&F^GI!q z@bzYD_$&NT`g3r1R=VJM_{PoiAG|*RQ996PAuQw_Y4aiOg^B9vFUB`XKKF@D5Ekh1@Ww+$$>#6#q7T=%BT(G~-Cv_i1_Oo}tSKaosiY#_B~M^sCel z7P~2@)~|*=U475PdM^YqA%S>DXP=LArO8=%tS0+2xrEO4v_tkaFnEZ?j$5SmY;O+l=Q^sut z(OX7n8|lq^=uL`CMN(IUNX!gr_i(y>XCNqwj4ide6@jy1dyxsVV=7?T@zh2JzqlW4)h5T{au-_kMoq+X+Ga> zOyRO`@bUUCDeh$ccBh9(&JVIlDKA^WJ<3u-@&O9~vXkvQ?tiKGMQp{R)7;tb#5Xq1uf_ti@7p z@ZzOknvR4DFjhqL-Cc;6F1*O4P`JK&zx}&nd?zu}VGaQ?uY@@xy{QyUp2EQ<0yG7g zu7OOCjJUb&fChiex$x}m`sy#DaSS6s@?fuSz{{};@Yp}g(|S{=$S6Sg(25vn@}s75 zD&KvK<3CovE*N7aNB5&@S!-X^e&;Rm(q$j78_e${8VIWiA zR_U*wl!cwURS64b(<;PB>hDVm!4|Q~v@ThHSEfaqi^XvE5GT65_+#K|iP52(?}Zl$ z;-%%^LMwVM4FV(k2_O2t!g#$EUTRUlrcj?kTkcf2Z)%S$@uilcR{F7B5g5{WPlWCf zfiW(1qIOogpF+0)u>SD+s;`K^zH+8?nX}XULmxS^L|1h`7n^v2fQ^Sc|BFBZgn^z} z!NQB<_Mz3?434JyR`{LPzVaQhFnQ0?Ka8R${=O=C_2l2)J%`z-ZI3#NWk%C}{HSn% z$TYRJR+*m6cQ^bz_z3;)hc+=6SHknJ@V)(W89C@|hy`j@gczz?07~6F;JG)et6pm% zbmAAV~vWo z{Poqq$0*$cfc${IO;i*_MCOM855M>JFIz$<6^*ip*xsV|HYiCu^cUKetKLXSWKf}hO0~WMIgc3h$E0GeDYa6yM9(< z${qm0;3<;X{b7 zb0m~oFY~n#IcUD8p44AnXh6Jh*>*4drUl7a6u$lawixjRqgXp}cq?sXa+K#l zb)5|s^d>T~NnvLrD?$p=U#kyYj;20|!k|x7Y2ul4+4UFUGPYu&NHRsStE`?cDH7vE z$a`6DbcF~s%$-rEaY^Oz{S@r!zdMx?XA{bMsBJC>{q=~krx-MZRq5|^HU67QziQ)@ zdDjAN`*jk6iPu$6{uA}cyMojBmcmU(8o4SLG3U6LS=l|8EW;v?qnwC>&aSFxz>cx- zDYB$nN%1M0C%a6 ziUMix-8U(kQ-3Hsnaks(=jtdwqe`($+_cyP zzl+R+S_lzy5r6*A1=r-YQ>I4^HlX4mH@)1=ZN5)7%04W_pAQcu@)ULd@Xsqae5ndX zh6Qk3Q%cP7UK*NMs9&ccf&zs-n!wAb1n#hQ8a89b9+eE}1UxafYSOP+p18Zvq?P5Vz^uh4?Ao$Hn3%kf6r83n~>1Ehz1%GQ#k1=y*(CW7d+a9 z{l_R~HXH_upUsD0&*D`+Xo>Z*O3!QsQmf2<&01Z9fM%5{)aASHP}zL<0VMR_oow^r z!&&sM;-qi85Wi3w5jLW)>Bc>mQc=EpF9X+6W|(OSRk1j__T5zqjQ|t<(k3&==sppE z{lY}UX`i*=BeYTm955PCMK5;2r>^_%)+c~Zl_~$`$WIP>cw21Cls;)HVvOgD5GVa> z;8U{nB+Bc2Men7-g|}lrV9e=#jrsa4yfppC>iSf6+H&XOuwO6zf#p(%IOw+p$o1Hv zdiS7sa;NKZ=grzO2zmr;c5XTdgYdm+rmQweiK9B<*SS0=M+eYe1U{d3>?FAcK7UKy zb?^V(WwdfVosTYJ$(@tyKVdCzO0UioJeePQkK0lc`x0q={yrb{gm0z9RvB`T|b8Rgut3;Jg~kiPZodh@+p78fApTXyf)%JUEX`c z{@wSu`0U-tTNf}-ItZG2C3UrgT<;~9$ed(-AWWhvBGM>0F2uqHz9h-L8?XKHVsn=) zH6}0z8+P81?()YMo%z4NXy5)D0LUCj;cUS1HgtYD!r}n&AiBq>47_%;g`l?OI z6U|<7CjkY!X+d_v**dui?u~NEx?El&ivssG%ix1Epor7&N}K7Cu4JjbMYo7$*Jlbn z7QzWn=ef|x=>fw(%xir)&^DKqMWO*X)580DfA(iVgK{<>f%=T zh~Qs{xbk}yudgNwWrGl3cSer#q|x@u*vMA!=%9+u)EDkCq*>tz_P8u+&&q*%GkDzF zFpwnnBy6oef|t!AHuod&za?zHXmG2ZTeYL?*BjNyW$Jk2UA4F+K9habtIDs}SHGEW zxxO85biNU`;t`JGV@`G1b&Obrb^aRFD-kH*BgFqUJu?iOpkzolZpR-QTnSqaD9tic zEt|&x5JfKgNeM)_^m&uB3--Q68snwV5Qc3-{^!4ldTEyP^$ zNw+dfX>t&r_e;$7=y|F(!+rF)@cDd$p1o4OY zo0N*a8Q2=0IHBRk#KZwHV=(zb&AU#-3oUOS=9r1Fc&4vT&Qq7HHzJW)$5H58<1SY^ znWP-LP7czvvHCScSi*ZukT}Gf!kH$rcJ?tY2FQGw~%+ButwYj;EUGDD48(!fA!a;tv4WN{~OdO%f%uq6?A_kXEixpZ80y z&$3s~!dCM0_{7XvgKwXE(U4r-9l}kXL7pA(g=UXg&}HK82q*rG0C+J^NgVek$LI4Y zJuuxp{gN9uS9c%z={sK!F*VBjkBKOL(+5pGjPGxixb|zAdsJ%|;}4g7_Ar+GH$RM5 zCXNToyF5~|Fh~ccHdcC`Y|o|D8-aI*Gw|6!;dS`pQlRs7$wsmXtgddi_|9vx2E^&hIJ z#k1h?iIl?+MqyK^`gs9wzZ1q6rZjX?K*C^~U;m$e_rDMSml^E;|F>nrtF6lPeU_Pv zaNivx0luq3`h9s1xdP^2SavXC>$J^r-Vcn;6AJNv6DO2JG3X$ zt=f+a^nVze*!w>v^dn0`Lnb4`S*&|H(=cPaOgxyVyZ^EWlb()6NHSd6>XsjxNq@o( z@h5l7o2nxkxUa1b@!#HO1t{cSnON{w_puP& zp7c@-#=Cg!5(aq+u{9W*of}{^X#-bJb_@_Gyz(=FfBGG1 zvi|WVEaZNJLu{+49g%wP%&X&gmFma|mvwfPw!9um>3YRMmbm>HUJ?1y?9xeVZi`F= z-F7sJ&v2$AVfcqDE6%{KZF=)#U+Ma4lrv240^xqfu9**pmCq)`D3WwYHuaBR!943F zwHT^AxZoM5Yrd5NM4D{H(iB)4;R=mcv29nl|YDwLHXH2yGi~JNEvam!WIqDw?l$T=8H#8N{=Sx>nQf1-d;Oz{XPdZly!*0RwZKTn?YLt!>bYh z*k>`$?zbsshd29uO-R&cF4c$sXo~+U=>HY;U$@HqSJ0>W8~?TF|F!7^RjxxJWLXt zx8s||3(nhfdufvr>>YTlK`1%RH75h3((%q-?HvHvG^Ev8>Hs2BqRaeMrv%t zzD1G6HKhyK#U#-7IXf+-RKWVLIY}?Y?KGA8 z1jvY1v!?45kQDM8hPq@OA28Sf>5#Mw>Uja7sgu_B)bR4D3|je*~lQGRyd0o)hq%`J3ZQ0&)K3jIeB9)Jpsn1_+L?*uQdoJyz(FGqRd6 z_`C>0$?H*@fT6C@S6c4*p=oQkoyP$k9E%A&V zbvg9x!op(qkb0he6AK@_l9?MzSF%T};)yUK6L*uT|hA})EL z_e$q>4jk)@cl_Q9C?D5jmWa zOW9g@?xjD6>TG_6VN$1SFxVISk#oB(c64)=^#8zJGo7Ivfc+V>+;TvwT&6OJwwH? zTS7hPoGJ5L2s^Fcea*oc)!mnN_P>`xpaJ+O*^6Rg6fWiF`W+8zLTXDX&@d zO|v51U>04)+KfYwxtJ*B+wJPd-(Tsk?14%T3zg>)!>RjgeFKHTcp7r$_t%5aXbXTf zgPP!t9k4yrh`;(hIl&;*l6)dwibDHi{zH@BlEULheFWah+>~3_cq5OzWT&lUuFA0N zbk*Q?XY7Tiux=Gl0Vqa^Gvl)oIY|A3p6s8yh4BDWw5PKr783A+d4lfw>o=CoCnlh- z*y#6d!ZJ5aO>J(wHKkDaTQM-uUM(pXwgbaw)JhUL$Y?BNcZ^F`Vq}ay+V6`?mDqK_ z`?#GLb0I~-QB8Hh6a&7hl}RD}T=3L(hbLbq{DN z#n7Lf?dIR#sLZ~jQ=Or0)qdVh#nI;|*ceynlJp{U5~KSrxupDtQed(cmg)OpcG}s{ zh!wy8zLVp2^{LVFlJeYbEl<38B`5Zyq&~R#zB+gyi(>YI>~is!MVqG+?U8>;is(p? zA_~7g08+%65#1JX5x=kie-b4AU&iyMc&#EmOkc=%!;h7{h2)@Ht2~b#e3{h{^6>g6*nN+gDxx&e)0`TBL=Rbnv&+44|~HrMA7y zu9pXOW*{K=TOch?*uDPQ1F@iqs43$AEteNC@Ykn{(VF9J{Q_*7if@v`z=~)zmK1sk zuh!TeXoLb)!XaZG8?Yjt`4s&7FSpNGlij%{J8fdGzJamV9C6JsEWM|1p}rJ)87-%c z^k9Ia%J1Fu!?*isb7HiKk2R}-W^NMh`GnN4H(pt#Q?ygeGv%Eyl#w7u zl!KHSv@?z+l7j;NN{*;{Ca+mJKh`Q{?0ryiso5?LK9D17dhjS2fZ-IbR0h4s%lBuU z(_Dg{P37&oUnw-Tt{cCZCA)~BkB?_K)SA}R7;PqeuoF0J6P>r1*5RXFxdnm%a)x1N z1Hmo%v;40<9ZX+IQiVZY7(=V5S^bDF z+_t)Xe1hHEy`DLe17lb*{HqUFtL)?TGmJ*dbkefAlV8VqQv$9SD7$3DJCa7XV z4flLmU(IEzXU^jGu>GQr2dRGu+4Y2Uh%f2zqzL-7Q+CwlciO~w>RGjCLWmwF56no_ zkE=Th1oWq47nx6a58ZB0md5k`qz?b#2#3Bdot@zLI=9kV9sG!#1vjPyGKGH)56t7Z zfUk#vRXdN(qXRDkp`J%aPnVSIcs0CKS#APg;_V?j1ev#vnp#M8y2?3e#puICpr|c%9~6Y_Fw>YRKECnkp8!ZMAHNO(B-0%W@+ftkOj=84WA^NHn;B4raWbnLM9 z`Hr*sK5N0w9MT~YIDo;sf&d2NE#MbYy0f9t_Y=XxS>K`_lr3IvAL( zzHQSe4LTSM#Zp z8hJ~;7F?EgOZb&VH+y}S*5;V(yO2!6zDc9ptzy1Ufq zPxt&_FqqVJd}i&k7SLaV{t7^S&% zIz~-z$SJ=eW@arEO(CGqZi}Vdg`a-@P^|I_sexAOYv#hXH!dm#bGJJo0r#?Gs45Gw z(l5Cq1Hm*LSd3Tt;=25Ij#0UbDb0mqgMliSqLu&Xj4obhNoO%mUK2|K8u-wc*J9sp zkQzwU_su|k#lphn5psGUNrt*XX><*b+72(y9u0l2#Vvb%avR&hffY>s^tN~?i?_iw zypn!Nw>lSXtgFLx$k=vx{p7HKZv7<9f$3F*BHA;^v2oP%V*_%;zy&s$zcSKg|{JtHOYj_b2F)zWOg~+^B@8 ze*gH}3Nv30HN8u3YnE&qx|~T*e8TU$LArgs`*x`U!NV5}9=<}Xun;_a=n5T5JWY=S z58pJ+P=bdqk;TIo0B(TU{0}`;AN~^5(uV^2MKYs9iZJ=?>^>#s!Ko!VX~|8q$H&(Y zl!;08(xW-$@vQ@+L9kZ5S9xrf)aIAI{*W6_aNMN{Oik*z5`+P3W4XdV&Sl&VpiQ`1 zwFeq{S3Z8NKhzzHFy#9d_mtv6UhF7O3 z{H9+thtlVdDtTtA6Nlq*#HwBA5VuRi0uKsD z{Yh4&C5>k=@X}3g<+q*D{s5$V!Z_uGg{6ey%d^A8sxFfn9@o0nz&PQy2^gn6FeULh z65%=OL*37RD5jR|m{^*DOAFR6i@Eb6u<(3aVW-rDMAu`2#`hXCKjLaqDd3*v(KXIY zKgbf+Y>N(PSwg$ZYJw&+_!s@=C!G3*AJ-cTk(K=rFMvPk@826F99=KK@YrqD9&ToB zma^OcX+cgb2ne>UCrB7YLBhy`ZRP<9<7?Qci=kfTt!QaaO#!WeBRTP2@q2|FYBmdU z$5?Nd=m6nfmK)9oy+TJe%q@9ccwHlPo2?q*m$`YpF zyvT|seL|?wiH9H{eMc@Rg37?*& zu3SHVF?K){1dmRc*K?Z(i{Dlyr*4E&imRAat71>pu7+3MCpB!1o2Al0#xEN%Bs_z% zo371N**?^*`_b+sQ;QdjzjOE*j>^6j8@3M}e_Gr@%^x)wO982+b4ku@R7V0hmG>XV zaetr1IN(kW68L4e%IHReEA|N!ziz z5cD=#2|~tmAY@cP*e|?=XYU@Y)84_X5-jfoO;HmWzicj&e8jQNjeB^McMTm6 z?NrPrJW+%BMU`$=aI?m-FNK-V6`}JEoO)}X4G6#$w>}+*$cI&!vxNKNnmAqvq^ zHW}((Qz}Clo)eR7=Q=8<#pn@W+#XLfq#u7%RaUeZGqz@X2Lp4$qBnf#jNZM@f?5SN z>WCCey9o;tf7Q;aPR!U(oG0yU$orgMtUG*dE`+HfR}0teRC0jux4krLpE={@Nk(^ zm*1*9blwhu%?~rLO>gWNxv5^gFU=U&tj+d(c@em*uY+oC5=}4ejBXL#H380Z^SLoI z6fsG*H}bM*syM0nOnN~Cf)I;H8&sFIG5Ue}G_LkwV-sd)Bed90Eq}0QfjB*@M%zfNtzJnVK zNox#^5oKD6>UXZdw#`rWKZoMSxmC9N%P@M@HK}+!hB3uJ^ z@C(;qc=;pV+_6Ixc*)PsvaQfcq^=OqA(u4Af%VtQ-he z6j9_M1pc@QtHOx+C=48mcF?~wHXww5>Qz!amh-lJo|8WeVx9a>)f0$VdZx2qlO}Ph z>f}UnEM^S0__rcu{Z68bF z>YU3@M9*zShi>b)YqeJ>wCA%l)3Ufhq_Y@<`9=8nv2uygpGVh@Z1w7ZuH4@kgeY=7 z5?w~$X=N`N7{X`H8D0%78aFIQbKZXCbOMFtnyJ2>hoB3DnE@0F2T_h>@oPBZ( zLDdb0P(_{(LqfNQul*#LHxnybpGu7ulxhtIvH;4Uw)`7_@|jJC)27Bk7mLI3XKB9( ztUs-*Gn7aeLHVoPYarjIR_%$>u~zBj1ewJc_zKH{e?A$_IoILcUx@m;g>gijBs5U+ zqUJ8#{X$@$zmqX>`W90=1S?s*0Vn;^@Zq6>HmvRPz1Dt9UPeRvEhc7ZH-VdR_uq|J z@Lj7XU%AV<4UYj)PC+ZU8MADI+e5vY2ovaJf8bG9y#(40C%V>&<$~%%!i8Qn$pN1m zd%qzjbRV$9H4E9NBS-WV39>&)kQq^e8_1ItKNd4%@(oV?O+x*x#5do*}eeH8If#;)qmo_ybT}fKzb2uG8j6+C1S8$}CQniP= zv-V!M8*PT%4X1o$4}TF@Q*6XMekZ*3xD~iqEc;l@j7JO+gjgSMy^fUlZPK=TtVxI| zW=849D};k+uJ8D0J0X4z=_Q=>u-+#_&DDe%9IA>*rW()L_~8H!Vd=;tVdn|g5bN`b zL!QZ-Lv4Bl5hn_+tSLj?JwZQ}S`ke|q<2&r$@tZNoxrVk&;sSS=whi)#^2EUVQFd@ z_7X1wPkDzjOow!%yE`!3xH8%ZB+FZkAKk_WKRe77hDzlvf}NEhlG0ZA!hT4JxK)Kk z&A12DjDc%o`l2F0ayu{(p4}5nmDB!XC>wrAWN;r?fm46Z|J2L0ya)yg+^J(udZM8q z1xNYhj_E21QuB+nqKzi1H!L50fTL8y=XxGO$gw4w@x2wQkdQpkhJ=-FaOX@slaFzs zU$h^rM7jyd;oy#JACF=HIk}9tG=d(aCC>9eBP&a`gHy8Hv*<*DE(t8pF-98q2nKMh={kKLLuA(YQ&lXTVx`bKz7 zd4kN?=WwR?%vb%#$dntffx|-}XuPqYUm2aW0;h1^W@jnDXpYUzvN*(C&!==WNaafvt@AT^mM7MV+ zUSVn$TpbQx<%TH-pVDa|skkgGqe=+NsHl)w-^*+{6V|DK3qO`r?F((iNJz7H+BXS; z7#}r4EQ96-RERO;!^0!fpJpt|7Am!rV6DHs#*u9>aOZf^dGNiZtmHb6gzi4NGHnnE z5cQaalMdya91t{BO#s;eh2s!G(qD~ENXpjTJU#?DRfwniL(9Ryqe%n9PiqXBm_rW- zK0A!k+uaTiQ;|GcHH%xdTB^KbngV`Rp629TL#UI;PL31yX&!g-n(z$e>3L)3fhzP& zt=!l!j0D-hHQQh$ND)EZK0o6jtEoz#34ZnB3X~LtV(B$*;sq%hFJE&m0D<3v?{fWz z2LtumLkzHrLi8!L^XeXhsQV*YdGCcj<%SX0h#fHmRhMz48--&R;?>9gpl44mY%J{8EVy6RZZRbxlClYH;Dhng$|q|`g>{*8C<93K9!kj~s-U;^*PqfU z&Ey_b9Dx3~i{e(#5c(NnsXbfC>#+#uHaDvds{6oLwke(w7Bs<3fsUrcq;^l?e)<51 z+46y5AFY6dc$h%FS3@eoMA*d(9QLVb?-zy!Dcl(!^33pRt6;jXA7s8Y;r(Ycw!$wq z#xNWx`T>0w;sw1&a?~)EQkVa>%G1lPgW4(5KE#)e*1Ob4;ZhF1+6Md1Bb*^Xa~ z0m{e^%q8g3)#Boy0xO1k5N`80pJ$2FEM7M<%An9bg|>Ii!k_<4P|m@hXT56D5<$ka z%5vb8v7q+`j^r=-Cis;S!-s3ou$4|*#0y%TbGGhh#}c?qH{{G1MDQS|0{(WvOiLZs zMMD?F5}+H0>Y8%WRm0u1_!04f;~RBoI|+LpWn6FN zG%?rCp%zGgjxH6f_EVT#dygV0TJmsFenUF=ruhNErYg`0E%R~%8 zG=qPPFRS^JN_`_9!0UWo2*`Z_%aTYvTtJCS|NaM+dhRL?wUNDUd_EWO5f@C)#=aSo z$eA%uu8S#aZdh~;&0ftf(>F^(t|e`E?6kn_BRqb_)bKs#WoLg)mB(#pVPRWn=dlDW z>7L@c@yo2KD5mV+O+{UPJX09sSUb6h8$&DAMpCzOu$riwAd?IGdt=+jFXw6yw9>wW@QqBr(N0!^8wY2s9`Y+|V}F{tr}CXVR0HxCm-UCWj>oe= zAf3^F2LeIc2W|j(9MGf^i^%z)9@PEXfc9A*M1J}XV@JXFT2pW640*z}pKt^(y4$ph6Krd}f1pMM^`EWus9im1Ey1R^3(Q@+>~lLaz1m89HJrf(D6vf? z5tDcEhbwGGFcHEk;O`f#2_K+LDRJLK3N>WhUzi%Q;TxrHs{9fQ|-O3jCClFSO>=v>qs^351r}{V;!lz+GNTA;*zti znY@z34ZS-EDy+{NL4_6Y-R%=De##Cj*Odlvgg-KWi5x=2lw?J_?W7*1ssuAfHvC$( z#XFCNBu6cdN5z1nhjuM+&d(*Z(VsIjy6Y?Hux@u^Se$nMJRkE9W#N_I3)O?>V8*pJ z1)OM(ec(j<8I}Gq5iQk6!OmZSi};C%;vH<>4Xft5SwJcAD-4pb6-JgD(Wb&y%$qq{ zTTh@Ihv)j7!d9H}&KW-r%E{B;L%a!Aw!D9ui#je-JH=vq8^+3E-z2YIYZ+xUlzL=8 z=#cW~mbU2hGoQH4D5h^mooY+#^Ya+15wbXxZ-YA3L4}^h!e9g@ZhqYk(|>Er*k^Th z7W5#mkUZW~Z=q!7x)Xd@YL7ptfa(6otkkM}l+N;FJWl99M#DUFQ?33*w`Cr|%d|7) zHBKY&PKGiruBG;Vkb4SZG=GJtWhj_&97sKeCaC7UBigdNC(%3zYeF9EB2)Ab97P^` znJ*|#c~d65yOggW0HMlzgR;$7G39lq(z=91`2{QfY-A&{1MjFhv{LW}t^aNxH@%uqt6OHIh4tH80 za3qoiSd6#L2cYgW@LlGD9VD;~(i z>~8tt!)ygtY?PB^go8GE-7Ok27ZPpk_La#*d-3a`UQ= z4aU=~zd0H+FhJEKP%1euhA=%Jh2TSlY*OA#gN75e-rcxd z%$&#i9eV>QES8TJ2Tpg*>=bUbmj3O3n1e4778tiDG6Oi%|4oC1%c;245**b2?G&`Jm71_DPtYPo$BhOgVTZYuqVj*ZkjcKSq)>rA8EAF0+2o8 zuP_@nlh;)}ud$wU3AKuV`5dlbrT2{?ioIA622|2TgK zqjK*wC?rUgCp_gz7*j(%$<75QdE3GxOuSuJ^qz{1r^j*?X_O+FpCD zdo^|7+8?+eJT#QwO>aIDgT*4ZlH`Y=B1`?0vpXVs&GWUZE|2p zWLY$s9K|BC+GM1pp7> z^;HA1s~H$zd@QDh-~9O`RcSe`pd(xS3DY2TDuw!(bY}P`0y89((e^k9GVvw$N<*Hk zR}Z|JO$IrMF3qOrM&N2iBtyjvWL=T!y5cr)SYE`)?iiuL(f(aZDU=QbS7YfPE+|na zjH&%n2B9cJf2b%BgkJhE1TeB*O=k@OW-z{{rkaoa<@*)-jiQ8>|H_Z7qM)g@4-nVw z!D9EyEm&g4h(&b(K(liF%t$1@^&F|EzvLrQ3dN~{j=w`WnO4=C+t7^H;(gmYrds8z697mqk>)5u9A(KB{I*WW9*W&tt*DV48f z#Oa{7A5f~ZB5nc0lDubKhb$6+AO2$3U;)SK>KelftJqyr?UwI+hxRW(ZJGjzuTx1H zD^?&rW6C)>?)N@uUd*F7dOQUn4tMvD+qR}k>LAj04C<4xmKo8bsMr^T!yJnnSm=#o zi(VO$HJI{(M7_V`0wY z#SNTd>1Bxz#_EbSxMTgitlC%%eifSLY(P&?6}MxjcfxSY{~C2H6ZFW;IvTr@te*9C zki#Dq6Gl+xBbQ=l%Vr;|MWIFi?MP7TEKF}@)dOCY^HQPYLWK<~O8hp!{^6u#D*)zv z9HTI$H+WVFoZ;7tMI{PN;4)v`l9OUJ`N;b5@Y=^?L6XoPlDzf;^nVEou^f+69QA=+ z+Hu&wm8|PBxPDmXuw}AbD4N0m+S3%ut1ki3 z8tI|&#Rj`m9)?6`DnuY+gov-0S>s9F4QtPyg{%DJ^(dK zMD^`Uq*OshidkCf^Xmr`9mX46ivkxg-m0EOfeUo-J2?I%L~;|jyeWYUdmhSaLmcO)p?e-c7)VZW+DOjS3^tzSW2NImOoDc_5r`EqfX zBqBUbAA2+ZcCckLE9HZEr(7WwuFbEtA4BmzF0u|l$qh0NSM^r6SjtK4vuxmg`Fc<> z_eX>1Y)m(B>~a#x2QK?P1mSNlndrU|t8i8tg5<*{ak^BB+uo=iP$Y8@$ooKASn&q4 z@-IFx!E>P^=XSW*bYZDonl^h+i#VTKT|BBcE4>d|GO<9ba}WA_7XT`tH%xdk{d-|T zGP_WTj-%ci4Ev_eFLuv+L6#4JsR<564SSrvcPMgo>SZPRTqJm>o-}YuY^>Z1D5YMr zDuAQ=uG5BgiGn$+Yba4QiqZ}rlMNJvc(4!i+`f*qYdP6ELRqnBE&F|8N`p_=T^w?E zupA6EM2ceGwwU%28R0L>>UWji9+ZBK~U6ESjarq10Fsov4c9OK-fcK}F7GAPNs#K~MdJ{uKvE&0-X8$7*JWzt8|Ju(TOn>2i!9j` zFmcN7O^IqEPb;R%^syo?*^GHDXvUiEJ1r8Y!%H;|o97~{cK3?#x7gR}zTSEHNn#&I z(^bh9O1=B)MW>7I6w&$2dKd!#>O2A$I6XA}3ZO0Iw#LH#b6(!^JC7YZzdPKUgvE+k z)0@7}aKg@nmx~*bu&eVypZQ-y<3}SC+k1(@c9@1a@jsiOnWZ3tq5?d`^gg^=I#&!L zj{Yc$GJ-YU!5VjW9Fjr$_zc^z3Al~7Y>4{092!Yrphd1ZzOp3US&Ujsf<2Z1?2$y5 zO@}`64f-{<>7?#Je=!DvXv$<04!K}uSeIU+j-dELm9;-!j23Ka(_*2qZoOq)I>*e_ zUt3}ugQ>2mTjLgt2Sp6pPm|s8*7Vm$ae*0wBl z!p*3EA)#bgL_*nP%mGEzxH+1^hZMy3^~=8(-~R@gl_rZ&if2wES+7+9L(m&MKiT@d z;Q2eBK919Z_G>EE#_hj*i~+XMuerU*ftlM8ckz`cux8!fx=akPz?p1H=|d+R32DZyujn0>BvC1Ez<&Z&>Q`cZ}@KX2axdso+~7?loRpg5|E z0@738V|~ zXrDCINe3?U{4|m3h~3Mamfq5eqOkipKECkw^bmHlL$D)lThrRGals3J|M;k1VVuT% zb4ye^_mnJ_4rAbQ{}9FeumigwKC9OaF8!JNR&cvX(`p5j*O1CbDu+)n}&D@7%eNX&5nD6WBUS6AMB1AyY`-vEk7 zP(t7Y*@C==I)0v5JU0;8O6j3dS_MbGt?rhram+{fIt4uV7T+ zHr~R;Qs#bdd|sjOvTx?7Mt^U2xSe&~#bsnZ+m1(^2n6KfueS8#(Ct~x$i;(SN{_eA zAx?par!u@Fff`*_e#<`zm$KsvE1!en&(f1Re!wbC4MO`@xtei<9MNN;OeQRo^OqlT z?i#>Q9%xGCLyzeC;kXBNnAaFU5$0_?JLX zqVCWIYXq2R4uI!y9x%EMobyOTU9vFKtgr6ruRyX0UAwM{lu(YoTTs7zZKBAKXp6Ta zI_43Vu#f+=KI|h6Ro)Ln{;b?GG7MT|o@?9w5+wj$qM{Sg} zxnYkY{m)YdAdNwXM*+luu8>~*@eC!@VS#&O{}K%;6G*VW$a1vG5{1P+!0et2JT~|i zKOk8Z#aCL8Dqv1;KL`*Y3%h=KOgc`#4!*hlVqMXb>!8f4i9IjVvPi7H@1r{*&_C+{ z$YQggN}swDbP@E4N6p#y`oy1w|0v)Z^=T614gIm7P9%%jLlqwX?SFz`agWfKAlXsx z&CCjwP}tJbEXDP)Ury?psl7XedPtK3DVhq{Oxe|B-%hgEX%w~Bvk9i}ATE*o*_Nap z$vy~MWAeYjpO~UAL?H_X3qDTxcMDs$gyD=?u5&hV+y9RT8+}|bnEr?L|8lUEQCrEu z-1OWI|I@*ii8hmiO0b_J$u%Jd+pX^Q%Re4$bS8-yy3FUd6tNGuOBCdHWme{W zFTYEj=+k0JciFQ^*w-%`k_;$vfW4Z! zG)BxHhv@(Eq=J7dvb)qz%=_%>pBhdkcZ@6SsmF6=YTU2ge--Tu;=|Z#!`N!WAcDgn zg8dd+5bF8A5k&BqwwH2$F2MhE8U*gfFmmQFa^^5{<}gI;Fhne=)cc&?VTf1+a)+^y zL4#o|_{L98!=-s>|Cw{buV(HJ;PWRvLuKYF;0 z!~g&NN;;$Si*+~k-;MQ=e*}fh$!iYw*1BYebg93z775BqZRs+zj5YZS2Mc0aWz_D9 z{Nk~N?r&SnxE8ptL~3X{i|ynZAMhq2EZtN1iFcF=6u*CXCo}CNJqiJKL4T2KR%(my z*_)Q9`tIGn9jiuA?u+?vb*&p!m$tn_1z0{JA1pK?ORTtIwyrmNvak0HAQOLMqbI6f zUwv2fM7S-zb(k)TOS^$set$yTAf9WK1M<}Pks~Mt$OKSD-xY$yU+fC)zg8VIBjs^z zl_(Zh+TgHaN+@m{P79zI8xI3t%Im*h&n_EarS3{^Lzl^3PTbb? zd_!@mK}+nvY&<~8Nlb02l**4$rfA?ITcbGY$Zr%U)PO%dTC*1AZiD7Ru7I6Q$pOfC zdxuBGOEE$35(zY42?Ulz6@35@_?vWv{>*Kz=T)i3nVF*ef=tjgmOM(!zLwgu`Ma;b zncDKawJbYay0=Xa+OKpT&o53qyhLcNbfsvvTv~qitRd9d3s9*`cMW5NH>!5J7t@!2 zDj?mns<*9+DEiVwmfLph{|@mt0D$mxlD3MZ2`k^=Ql`*R4kYs1Zizik+@NjoU2WeTp)&z^R~OSR9|YJ0 z$^n6;dqceQGLUJ_ojCjcW=b7*fpr~T#t$Q=VEb*G9yr=6vnWMU|}3 zqS@mJ5?FJmYhBOfRjtMa0ou94vcCkN5jv-h8-4C3p zOzCH)Tx#G(*E*JB$4zr#=93sdtr4slGREP-BQZ@SWT-?PO`EZl+uRUzrCVO2XX-bx z`Sw9VtML|)hmLAL{7Owmx&T=meTmw+`17TVXxX8JWk*oDM>La}1v(HlvcS!qMuJ~C z75cQ!TP-9#p~hSm^pMKp$u3Hv4p1#wi+RtL8&hmubF|kQy9`m*;FH4DTyenB-78CQ zzsMHHJtT=MYey)e*u2=?*RxWXl_pTTvr*o@Rei~igQjm7o!SzPow;~Ry}u3pphw-N zdNFnRz7T8QF!>U7qPGAjJ0phOusuGY<-C46YCi{dO|TurHX`IszM)QrXpQtu;2M!R z!CNF78-ksY$S~x$BPbnWoz3~ho~528J}bF%VL)6xvQrb;H_!}VdqrKzd?Eg$hq9}U z{P^Tf{AgQ|Onru1=x3=bABa&`_egxLR$S6*Bs8TFloV?BHrG1E%c&Q=MdQfbCLx{d zxHjOJ?%JjC%Y`;1DV3cFLEaZnbBkb~0e#gT_+O#B*3E{ppZ#}&C*3PX(gi8w2(l6q zO$G=Nq5*h%0O(R173Xd$G%ccwDlmLl>(-q3l9>c)f`EqmshpB?4|?5Cy3jyq{cL5T z;+<{B_A~j(V~E~tus6$8#YtS+R&&R=gs`$o;y|fb(h&Sm>RP1c6k!! zZt(#?d0X4ECCN{CY7ZzC(8QKK?W_mS6mqU1Y36BK@jGRLB+3g@*Y$@6k04+HhB<+@ z0s*fh?9yFPR3vC=;pa&x;x!}xekBaz)wcM6Jnr0u5$LN;_LO#6dxlDKWFGX7-y7!n zzu|i`7_n+n12s67q}fpdFi^lGgUwEa6a1Hh0#i6hEA$HQ52HIz16lGX|Lo<`>ujM- zcKf+|>|<*XJ;3j+PBiWe5n4?!U5Ds_HQry*Ev}puQ9YlEoX%i3jz^fha-$#cMST89 zF*q;u7>LkwJGG_A&!a3stQoMf%{!XU0xmW^wdGWnSZ##R15qjLsyq3C=2csnlZbdM z#xAvF%P28_Xs)pCo|gKB)-CtrD%*sEbWkT8!K{PV~g+7^PqKX&O`h6S`z0 z{Q->_e^r7;QTGr#rXD0REo%JaeTxe1qoyQ_{zu|e@V50+DEl;R#p7ekW{r<2>;8Ye~SMj=w zt$M`YU7SHNzZH>G-=;bMN8hh2^_CEMeyhwE{MIySDZ>;}ecDyGS(fTy8xXZ1KzytI zX(2i=P8?5V+{;Z~vMsu_-^L%jc zL|-EHAm;JnQNmi!*9Y-(^&rY8VBl+l+3!b}-eY#XSEwEY)!s)cVkz|{t32~b++*b= zl%77xKkC3RCUmWQ*LitNMVaQ1HQ4VWbgiqLns%O}iu&Ke+gJCZu~S6C?k>-tDxSYsCp@L>Xoq$qu^SQ;6xb z>@23)$Ep{u!fpdMmYQ($WqkR`!y?2ZxyHw}@52_HVjrdG+)@ZWAjAy8Y%9^syG#ib z7N#M;uIMCdt(d)rR}-&{Gr>f7-lA8O8t?JWa}M7G%&0sF?_(dng1dxpid8uLcP|&C zn8!z$91tPuU^~*b);LpaM%yPc&An$U4`TX$M)=8)zk|iw_#YJeqF5){z)nqC&w?Ax zX*$*ai$OEGsbHUV1fVM=@QU0D3aY6I;|e?DvTkJGO3}uV%dcs;=+vskE0j%Pq=wy8rN2h#~KACSDW~k$+{n#Mtt@^d4XD`@GX1 zRdr_&o1pn7NoPLS*76GE7o3aCiE;Yj&`_b5mAac*oT=9Q>EM=m(}+!SjX%`hPNa|g zWpt+xzw(!t9&SR@bD_M7Q^+d*#N8aV8p_; z#8%6YvbROYmojcZko8lw^Xl)ht2s5X`t|Ks9t*j(wJi3hY(?M1ZeOQSbL0pIY<2CM zwC0R`>>^Hum9E2vb+d)+L5m6Z5$7H!w`H5^Rf)pw;KS94=1qRnz#YXdO-Ch!brI1{ z(~hsV&D!2=?QOy!MRdXadDR|bozDEQ`ClKgh!74|i3g{j7(Zhf?osr6(&020=7X3+76Ht8XcYk?YE=IUo>BQHkOP9F_nVO^s_H))K%Sb2B z-O|z*aWI_Kb8`3HH1>MXs9{~$gXW<+fT*T+r)AiAf7uNoozv~wK`K(>Nf+~9D80?5;^E)X$1)?Fr(IPx>;RRnSq2=tP zT(E47@7{Uu>5nTJhsot+E{xaF^2*_buxd2p8GD4DXu*DG=P=t_bUuzoi=68iX2#s` zrQB__>_ld?`Myb78LXj)GBYu^harb8b=JGMJd!FTliwpW-;94gy0nUWMro_&bcUDE zFg{d6zs9E_HXc=bZUBb>C*&t-2gA)79TZ>vHqlSs=|LJcLR8S4>}8SKF7rW7b7uTx zv07MOXLC8%xQ{U2j#gz1a*;zUwS=BMVQ$kJTfXyd?gGH(UPbZwq}01Ll7$iMx>y?< z-J)`pD?$$yx)LGs2NXRkYBYXa&XC01ru;JR(=1AbSEFgDo#yP@#zJg=cxqz=ubk5{ zwo2~?Ol!Ydl-BbnCRzvCmQ^=~_)HN}j5;(&CxfW39~@V2Rj2%dQa)LS%-gMw-087Z zR%6RMOn>appZ`V*y}5)@oPxE(PM6%9s&vLY%*}1$>#@Wm>B3Hbqj+ZNd--Y{qz4%` zJj!+y>)gmcz&n<8`PmG(EXH(^{~n|>dT4=BOb_q;?huznLXVh=*;{s*@RzIc-OQ)Z z8EPc&+?%&bdc5piZ~hyXU1xR+DGT;93cz~SbyYqS-J+I6s=R|*VW-$~wCq^s25(QL zA+r)8meL$8x)}WGrB%A~h!`k6v-pxE>VkOY8h#W1V1vP5R{;@%U2rtG$BgX=h)eRA zErmW9BEL;1U@mn7jd!7I_|Qn28V51u1YC+$sj9BN1OtW z<1ShX@-#S?)(Nd#Up1-yU9L21tL25dbq&QTbOsqZ(281cntf8-e-r--Pg~#caLds3 zcvBsHy%Iyj3nmm@ql(&xLz;O9It_@qw0S-5g{4ZhHmr$prVN)M+s_z9HMHv5&G+NT z=>L%@3lO+PU^K~%_s0?Pc?fn=smGhEZ<#vc_}#<57gFH4lcbE~bd-@Tf9mzv<)Xf#j3&ON*J zo8J4v(`F1^?(` z!x9pBkc>qzo-R{P+DwGWmwMH{=TzHepRXLc16^`=?=V;M@9-*GgY2cD>a<8z=NxXv zFd)KgjCOfNhR)8PSn=BsqOdha+uIxTaHSO$7yh1d7A~LCh$8?4pd8lnI>WQzm|N;D ztbG(dH2hHuguVhh1J>7gUZtOII3X&bN2-Y1ukX(wvgGc1@RN8qVt2I!+KwFR8(gKx zS?5@EdGL*{{vKhDO<|#m#6CO}ClIbBEy1cRowz}bF-8O0pREn8`ZPFdHPKKy4c zO|Qu9ErfM)o*ws;3Z460)Zc;si1X=C_13jRL)+&i+r0Stqns3Nx47(wAjDxSHhuKn zL3uvfzWr9{Ve8h|m-f~Vxqqb%BZy{bmlew-&?2tk^r~fyEm+};lGhW7xzq%w08f4t zPl4l|KfdJbkmqz@+PX8D7W`yhPV3GUizStkq%mUnx-+U`np3?V@d!>A>%P@i&Dr;c zD0p@~cB9LR|AuECYhGWkz5vIvNNAIeJF8M83U!E-*!z~P3H58kQ=BR<4GFN+-eKoh zCmOb8L=|^tOedA*N)F7lTr)44s8ZP$4boN$)DwUb$2g?B%rO6biZLac*!HS)J| z{7%+B(*{!#uIfr6_YQeI!^Zj$c9vB(zOgS^^LlEBDyAzLY#B~Rtgf}EURzV7dDl8M z$Q+C~08?t}T*wmqIM)`RK2Tj?fwHpP7-w?0Hadv?3@fV-lb> zsV#8llSAz0qQXyYx>q=F8K>Y%W7VqIyc?$3U%8>PV`q=e&iS(@RZoIXB zv97K{Pw9i!u%OmUJfqm2IKv$eBQLmL7267iX83>;YA3!?9BOF$y@DBV&nBp@9Z(|u zU-bRY3$hDTz~Zk$&UU}TIs^hfavnWIfqff}D8lzCo+kZ;cHh3}|G*~eEibNw9RHQp z{qvY{AK$n9Sp7F)tzHjuJRF!YXEeU?$j}d4&}j8V_T;X=?!=(s9)aUG%%c7M@NgAK zB+(+>YkwDt6+FXO2fuqI+`>Wc9Q?A2h=I@QIMh63^9Cq31{`$g>9~H14t&w~KPlv4 ztRl2q=!?Elhz;1}8K_zuJnA4a3^M_BmiYY35J Date: Thu, 18 Dec 2025 17:58:23 +0000 Subject: [PATCH 23/67] fix: improves upload security for PDFs and SVGs (#14929) #### What? Improves upload security by closing validation gaps for `PDF` and `SVG` files, preventing malicious files from bypassing MIME type restrictions. #### Why? - **PDFs**: Corrupted PDFs with a manipulated content type could bypass detection when no `fileTypeFromBuffer` was undefined, allowing unauthorized file types pass. - **SVGs**: SVGs can contain malicious scripts that execute when rendered, currently we do not check the SVG for anything potentially harmful #### How? - Added extension validation: If the PDF returns no buffer, we have an additional check on the `ext` which closes the validation gap - Added SVG sanitization: New `validateSvg` utility checks for attack elements including scripts, event handlers, foreign objects, iframes etc --- .../src/uploads/checkFileRestrictions.ts | 35 ++++++++++- packages/payload/src/uploads/validateSvg.ts | 58 +++++++++++++++++++ .../payload/src/utilities/validateMimeType.ts | 5 ++ test/uploads/corrupt.svg | 7 +++ test/uploads/int.spec.ts | 29 ++++++++++ test/uploads/test.html | 1 + 6 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 packages/payload/src/uploads/validateSvg.ts create mode 100644 test/uploads/corrupt.svg create mode 100644 test/uploads/test.html diff --git a/packages/payload/src/uploads/checkFileRestrictions.ts b/packages/payload/src/uploads/checkFileRestrictions.ts index e2943c65439..3717dd6ba15 100644 --- a/packages/payload/src/uploads/checkFileRestrictions.ts +++ b/packages/payload/src/uploads/checkFileRestrictions.ts @@ -6,6 +6,8 @@ import { ValidationError } from '../errors/index.js' import { validateMimeType } from '../utilities/validateMimeType.js' import { validatePDF } from '../utilities/validatePDF.js' import { detectSvgFromXml } from './detectSvgFromXml.js' +import { getFileTypeFallback } from './getFileTypeFallback.js' +import { validateSvg } from './validateSvg.js' /** * Restricted file types and their extensions. @@ -103,8 +105,37 @@ export const checkFileRestrictions = async ({ } } - if (!detected && expectsDetectableType(typeFromExtension) && !useTempFiles) { - errors.push(`File buffer returned no detectable MIME type.`) + if (!detected && !useTempFiles) { + const mimeTypeFromExtension = getFileTypeFallback(file.name).mime + const extIsValid = validateMimeType(mimeTypeFromExtension, configMimeTypes) + + if (!extIsValid) { + errors.push( + `File type ${mimeTypeFromExtension} (from extension ${typeFromExtension}) is not allowed.`, + ) + } else { + // SVG security check (text-based files not detectable by buffer) + if (typeFromExtension.toLowerCase() === 'svg') { + const isSafeSvg = validateSvg(file.data) + if (!isSafeSvg) { + errors.push('SVG file contains potentially harmful content.') + } + } + + // PDF validation + if (mimeTypeFromExtension === 'application/pdf') { + const isValidPDF = validatePDF(file.data) + if (!isValidPDF) { + errors.push('Invalid or corrupted PDF file.') + } + } + } + + if (expectsDetectableType(mimeTypeFromExtension)) { + req.payload.logger.warn( + `File buffer returned no detectable MIME type for ${file.name}. Falling back to extension-based validation.`, + ) + } } const passesMimeTypeCheck = detected?.mime && validateMimeType(detected.mime, configMimeTypes) diff --git a/packages/payload/src/uploads/validateSvg.ts b/packages/payload/src/uploads/validateSvg.ts new file mode 100644 index 00000000000..c4ae88e2490 --- /dev/null +++ b/packages/payload/src/uploads/validateSvg.ts @@ -0,0 +1,58 @@ +/** + * Validate SVG content for security vulnerabilities + * Detects and blocks malicious patterns commonly used in SVG-based attacks + */ +export function validateSvg(buffer: Buffer): boolean { + try { + const content = buffer.toString('utf8') + + const dangerousPatterns = [ + // Script tags + /]/i, + /<\/script>/i, + + // Event handlers (onclick, onload, onerror, etc.) + /\son\w+\s*=/i, + + // JavaScript URLs + /javascript:/i, + /data:text\/html/i, + + // Foreign objects (can embed HTML) + /]/i, + + // Embedded iframes + /]/i, + + // Embedded objects and embeds + /]/i, + /]/i, + + // Base64 encoded scripts (common obfuscation technique) + /data:image\/svg\+xml;base64,[\w+/]*PHNjcmlwdA/i, // + diff --git a/test/uploads/int.spec.ts b/test/uploads/int.spec.ts index 2e8f251d67c..4644d1e9095 100644 --- a/test/uploads/int.spec.ts +++ b/test/uploads/int.spec.ts @@ -287,6 +287,21 @@ describe('Collections - Uploads', () => { expect(response.status).toBe(400) }) + it('should not allow html file to be uploaded to PDF only collection', async () => { + const formData = new FormData() + const filePath = path.join(dirname, './test.html') + const { file, handle } = await createStreamableFile(filePath, 'application/pdf') + formData.append('file', file) + formData.append('contentType', 'application/pdf') + + const response = await restClient.POST(`/${pdfOnlySlug}`, { + body: formData, + }) + await handle.close() + + expect(response.status).toBe(400) + }) + it('should not allow invalid mimeType to be created', async () => { const formData = new FormData() const filePath = path.join(dirname, './image.jpg') @@ -302,6 +317,20 @@ describe('Collections - Uploads', () => { expect(response.status).toBe(400) }) + + it('should not allow corrupted SVG to be created', async () => { + const formData = new FormData() + const filePath = path.join(dirname, './corrupt.svg') + const { file, handle } = await createStreamableFile(filePath) + formData.append('file', file) + + const response = await restClient.POST(`/${svgOnlySlug}`, { + body: formData, + }) + await handle.close() + + expect(response.status).toBe(400) + }) }) describe('update', () => { it('should replace image and delete old files - by ID', async () => { diff --git a/test/uploads/test.html b/test/uploads/test.html new file mode 100644 index 00000000000..1005b0ad3fd --- /dev/null +++ b/test/uploads/test.html @@ -0,0 +1 @@ +
hello
From f44de413d70fb26e7321850d31f25c523d25d677 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Thu, 18 Dec 2025 11:23:35 -0800 Subject: [PATCH 24/67] docs: update screenshot for fields/rich-text (#14979) Updates the screenshot to use lexical instead of slate. Before: https://payloadcms.com/docs/fields/rich-text After: https://payloadcms.com/docs/dynamic/fields/rich-text?branch=AlessioGr-patch-1 --- docs/fields/rich-text.mdx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/fields/rich-text.mdx b/docs/fields/rich-text.mdx index 9a864238d2c..7cc0cc95689 100644 --- a/docs/fields/rich-text.mdx +++ b/docs/fields/rich-text.mdx @@ -12,13 +12,12 @@ Consistent with Payload's goal of making you learn as little of Payload as possi Instead, you can invest your time and effort into learning the underlying open-source tools that will allow you to apply your learnings elsewhere as well. - + ## Config Options | Option | Description | From cc09a3314cadfb424acf97a5a9531b678e4c257b Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Thu, 18 Dec 2025 13:15:15 -0800 Subject: [PATCH 25/67] refactor: replace deprecated url.parse api usage (#14980) Replaces `URL.parse()` usage which is now deprecated with `new URL()`. Fixes https://github.com/payloadcms/payload/issues/14978 --- packages/payload/src/auth/operations/refresh.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/payload/src/auth/operations/refresh.ts b/packages/payload/src/auth/operations/refresh.ts index 4c2fe5ee8aa..466da9cd675 100644 --- a/packages/payload/src/auth/operations/refresh.ts +++ b/packages/payload/src/auth/operations/refresh.ts @@ -1,5 +1,3 @@ -import url from 'url' - import type { Collection } from '../../collections/config/types.js' import type { Document, PayloadRequest } from '../../types/index.js' @@ -64,8 +62,9 @@ export const refreshOperation = async (incomingArgs: Arguments): Promise throw new Forbidden(args.req.t) } - const parsedURL = url.parse(args.req.url!) - const isGraphQL = parsedURL.pathname === config.routes.graphQL + const pathname = new URL(args.req.url!).pathname + + const isGraphQL = pathname === config.routes.graphQL let user = await req.payload.db.findOne({ collection: collectionConfig.slug, From b157d4634fa6faed7f8a5291ec50a404c89f3cf2 Mon Sep 17 00:00:00 2001 From: Jake Date: Fri, 19 Dec 2025 09:26:40 -0500 Subject: [PATCH 26/67] fix: get field by path for blocks (#14984) It's currently not possible to use `getFieldByPath` to find a field nested within a block. For example: ```ts // This return undefined const fieldInBlock = getFieldByPath({ path: 'blocks.block2.text2' , fields: [ { type: 'blocks', name: 'blocks', blocks: [ { slug: 'block1', fields: [ { name: 'text1', type: 'text', }, ], }, { slug: 'block2', fields: [ { name: 'text2', type: 'text', }, ], }, ], } ] }) ``` This is because the function is ignoring block slugs and looping over each block's fields until one is found. Except they are never found because the path is not trimmed for the next iteration. If the same field exists across different blocks, I would also imagine the wrong schema could get matched. --- .../src/utilities/getFieldByPath.spec.ts | 33 +++++++++++++++++++ .../payload/src/utilities/getFieldByPath.ts | 33 ++++++++++++------- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/packages/payload/src/utilities/getFieldByPath.spec.ts b/packages/payload/src/utilities/getFieldByPath.spec.ts index 414b38147bb..12b56dff88e 100644 --- a/packages/payload/src/utilities/getFieldByPath.spec.ts +++ b/packages/payload/src/utilities/getFieldByPath.spec.ts @@ -60,6 +60,30 @@ const fields = flattenAllFields({ }, ], }, + { + type: 'blocks', + name: 'blocks', + blocks: [ + { + slug: 'block1', + fields: [ + { + name: 'text1', + type: 'text', + }, + ], + }, + { + slug: 'block2', + fields: [ + { + name: 'text2', + type: 'text', + }, + ], + }, + ], + }, ], }) @@ -105,4 +129,13 @@ describe('getFieldByPath', () => { expect(assert_7.pathHasLocalized).toBe(true) expect(assert_7.localizedPath).toBe('tab.localizedArray..text') }) + + it('gets field nested within block', () => { + const fieldInBlock = getFieldByPath({ fields, path: 'blocks.block2.text2' }) + expect(fieldInBlock?.field).toBeDefined() + + const sourceField = (fields[4] as any).blocks?.[1].flattenedFields?.[0] + expect(sourceField).toBeDefined() + expect(fieldInBlock?.field).toBe(sourceField) + }) }) diff --git a/packages/payload/src/utilities/getFieldByPath.ts b/packages/payload/src/utilities/getFieldByPath.ts index 58667f7d56d..379c83d0489 100644 --- a/packages/payload/src/utilities/getFieldByPath.ts +++ b/packages/payload/src/utilities/getFieldByPath.ts @@ -2,10 +2,9 @@ import type { SanitizedConfig } from '../config/types.js' import type { FlattenedField } from '../fields/config/types.js' /** - * Get the field from by its path. - * Can accept nested paths, e.g: group.title, array.group.title - * If there were any localized on the path, pathHasLocalized will be true and localizedPath will look like: - * group..title // group is localized here + * Get the field by its schema path, e.g. group.title, array.group.title + * If there were any localized on the path, `pathHasLocalized` will be true and `localizedPath` will look like: + * `group..title` // group is localized here */ export const getFieldByPath = ({ config, @@ -18,6 +17,9 @@ export const getFieldByPath = ({ fields: FlattenedField[] includeRelationships?: boolean localizedPath?: string + /** + * The schema path, e.g. `array.group.title` + */ path: string }): { field: FlattenedField @@ -34,6 +36,7 @@ export const getFieldByPath = ({ while (segments.length > 0) { const segment = segments.shift() + localizedPath = `${localizedPath ? `${localizedPath}.` : ''}${segment}` const field = currentFields.find((each) => each.name === segment) @@ -68,19 +71,25 @@ export const getFieldByPath = ({ } } - if ('blocks' in field) { - for (const block of field.blocks) { - const maybeField = getFieldByPath({ + if ('blocks' in field && segments.length > 0) { + const blockSlug = segments[0] + const block = field.blocks.find((b) => b.slug === blockSlug) + + if (block) { + segments.shift() + localizedPath = `${localizedPath}.${blockSlug}` + + if (segments.length === 0) { + return null + } + + return getFieldByPath({ config, fields: block.flattenedFields, includeRelationships, localizedPath, - path: [...segments].join('.'), + path: segments.join('.'), }) - - if (maybeField) { - return maybeField - } } } From d0c7b97ae8c21920d99467a312c3cf110d8de574 Mon Sep 17 00:00:00 2001 From: Kendell <1900724+kendelljoseph@users.noreply.github.com> Date: Fri, 19 Dec 2025 09:58:04 -0500 Subject: [PATCH 27/67] fix(plugin-mcp): adds collection and strategy to user (#14981) Fixes: https://github.com/payloadcms/payload/issues/14923 Correctly adds `collectionSlug` and `_strategy` to the `user` when using MCP operations. --- packages/plugin-mcp/src/endpoints/mcp.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/plugin-mcp/src/endpoints/mcp.ts b/packages/plugin-mcp/src/endpoints/mcp.ts index c80840bfe21..8ebe7fecc3b 100644 --- a/packages/plugin-mcp/src/endpoints/mcp.ts +++ b/packages/plugin-mcp/src/endpoints/mcp.ts @@ -1,5 +1,5 @@ import crypto from 'crypto' -import { type PayloadHandler, UnauthorizedError, type Where } from 'payload' +import { type PayloadHandler, type TypedUser, UnauthorizedError, type Where } from 'payload' import type { MCPAccessSettings, PluginMCPServerConfig } from '../types.js' @@ -57,6 +57,14 @@ export const initializeMCPHandler = (pluginOptions: PluginMCPServerConfig) => { payload.logger.info('[payload-mcp] API Key is valid') } + const user = docs[0]?.user as TypedUser + const customUserCollection = + typeof pluginOptions.userCollection === 'string' + ? pluginOptions.userCollection + : pluginOptions.userCollection?.slug + user.collection = customUserCollection ?? 'users' + user._strategy = 'mcp-api-key' as const + return docs[0] as unknown as MCPAccessSettings } From 400c3bf298adaa596263cf891d63a73a03a2bce5 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Fri, 19 Dec 2025 07:07:16 -0800 Subject: [PATCH 28/67] test: improve database test setup (#14982) This PR brings over most of the test suite improvements I made [here](https://github.com/payloadcms/enterprise-plugins/pull/249) to our payload monorepo. - Replaces mongodb-memory-server with an actual mongo db using the mongodb-community-server docker image. This unblocks the vitest migration PR (https://github.com/payloadcms/payload/pull/14337). Currently, debugging does not work in that PR - this is due to the global setup script that has to start the mongo memory db. - Just like postgres, all mongodb databases now support vector search. mongodb-atlas-local supports it natively, and for mongodb-community-server, our docker compose script installs `mongot`, which unlocks support for vector search. This means we could add [vector storage/search tests similar to the ones we have for postgres](https://github.com/payloadcms/payload/blob/main/test/database/postgres-vector.int.spec.ts) - Int tests now run against both mongodb adapters: mongodb (mongodb-community-server) and mongodb-atlas (mongodb-atlas-local) - Adds docker scripts for mongodb, mongodb-atlas, and postgres, documented in README.md. Updates default db adapter URLs to automatically pick up databases started by those scripts. This makes it easier for people cloning the repo to get started with consistent databases matching CI - no complicated manual installation steps - Simplified db setup handling locally in CI. In CI, everything is scoped to `.github/actions/start-database/action.yml`. Locally, everything is scoped to `test/helpers/db`. Each database adapter now shares the same username, password and db name - Use consistent db connection string env variables, all ending with _URL - Updates the CONTRIBUTING.md with up-to-date information and adds a new database section. We now recommend everyone to use those docker scripts --- .env.example | 5 + .github/actions/setup/action.yml | 4 +- .github/actions/start-database/action.yml | 65 +++++++ .github/workflows/main.yml | 114 ++++------- .github/workflows/post-release-templates.yml | 10 +- CLAUDE.md | 1 - CONTRIBUTING.md | 75 +++++-- docs/configuration/environment-vars.mdx | 2 +- docs/configuration/overview.mdx | 2 +- docs/database/mongodb.mdx | 6 +- docs/database/overview.mdx | 2 +- docs/database/postgres.mdx | 2 +- docs/getting-started/installation.mdx | 2 +- docs/production/deployment.mdx | 6 +- examples/astro/payload/.env.example | 2 +- examples/astro/payload/docker-compose.yml | 8 +- examples/astro/payload/src/payload.config.ts | 2 +- examples/astro/website/.env.example | 2 +- examples/auth/.env.example | 2 +- examples/auth/src/payload.config.ts | 2 +- examples/custom-components/.env.example | 2 +- .../custom-components/src/payload.config.ts | 2 +- examples/custom-server/src/payload.config.ts | 2 +- examples/draft-preview/.env.example | 2 +- examples/draft-preview/src/payload.config.ts | 2 +- examples/email/.env.example | 2 +- examples/email/src/payload.config.ts | 2 +- examples/form-builder/.env.example | 2 +- examples/form-builder/src/payload.config.ts | 2 +- examples/live-preview/.env.example | 2 +- examples/live-preview/src/payload.config.ts | 2 +- examples/localization/.env.example | 2 +- examples/localization/src/payload.config.ts | 2 +- examples/multi-tenant/.env.example | 4 +- examples/multi-tenant/src/payload.config.ts | 2 +- examples/remix/payload/.env.example | 2 +- examples/remix/payload/docker-compose.yml | 8 +- examples/remix/payload/src/payload.config.ts | 2 +- examples/remix/website/.env.example | 2 +- examples/tailwind-shadcn-ui/.env.example | 2 +- .../tailwind-shadcn-ui/src/payload.config.ts | 2 +- examples/whitelabel/.env.example | 2 +- examples/whitelabel/src/payload.config.ts | 2 +- package.json | 19 +- .../src/lib/ast/adapter-config.ts | 2 +- .../src/lib/ast/payload-config.spec.ts | 8 +- .../src/lib/ast/payload-config.ts | 2 +- .../src/lib/configure-payload-config.ts | 2 +- .../src/lib/manage-env-files.spec.ts | 22 +-- .../src/lib/manage-env-files.ts | 10 +- packages/db-mongodb/README.md | 2 +- packages/db-postgres/README.md | 2 +- packages/db-sqlite/README.md | 2 +- packages/db-vercel-postgres/README.md | 2 +- packages/plugin-mcp/src/mcp/helpers/config.ts | 2 +- pnpm-lock.yaml | 14 +- templates/_agents/AGENTS.md | 2 +- templates/_agents/rules/adapters.md | 4 +- templates/_agents/rules/payload-overview.md | 2 +- templates/_template/.env.example | 2 +- templates/_template/docker-compose.yml | 8 +- templates/_template/src/payload.config.ts | 2 +- templates/blank/.cursor/rules/adapters.md | 4 +- .../blank/.cursor/rules/payload-overview.md | 2 +- templates/blank/.env.example | 2 +- templates/blank/AGENTS.md | 2 +- templates/blank/README.md | 6 +- templates/blank/docker-compose.yml | 8 +- templates/blank/src/payload.config.ts | 2 +- templates/ecommerce/.cursor/rules/adapters.md | 4 +- .../.cursor/rules/payload-overview.md | 2 +- templates/ecommerce/.env.example | 2 +- templates/ecommerce/AGENTS.md | 2 +- templates/ecommerce/src/payload.config.ts | 2 +- templates/plugin/README.md | 2 +- templates/plugin/dev/.env.example | 2 +- templates/plugin/dev/payload.config.ts | 4 +- templates/website/.cursor/rules/adapters.md | 4 +- .../website/.cursor/rules/payload-overview.md | 2 +- templates/website/.env.example | 4 +- templates/website/AGENTS.md | 2 +- templates/website/src/environment.d.ts | 2 +- templates/website/src/payload.config.ts | 2 +- .../.cursor/rules/adapters.md | 4 +- .../.cursor/rules/payload-overview.md | 2 +- templates/with-cloudflare-d1/AGENTS.md | 2 +- .../with-postgres/.cursor/rules/adapters.md | 4 +- .../.cursor/rules/payload-overview.md | 2 +- templates/with-postgres/.env.example | 4 +- templates/with-postgres/AGENTS.md | 2 +- templates/with-postgres/docker-compose.yml | 8 +- templates/with-postgres/src/payload.config.ts | 2 +- .../.cursor/rules/adapters.md | 4 +- .../.cursor/rules/payload-overview.md | 2 +- templates/with-vercel-mongodb/.env.example | 4 +- templates/with-vercel-mongodb/AGENTS.md | 2 +- templates/with-vercel-mongodb/README.md | 6 +- .../with-vercel-mongodb/docker-compose.yml | 8 +- .../with-vercel-mongodb/src/payload.config.ts | 2 +- .../.cursor/rules/adapters.md | 4 +- .../.cursor/rules/payload-overview.md | 2 +- templates/with-vercel-postgres/AGENTS.md | 2 +- .../with-vercel-postgres/docker-compose.yml | 8 +- .../.cursor/rules/adapters.md | 4 +- .../.cursor/rules/payload-overview.md | 2 +- templates/with-vercel-website/AGENTS.md | 2 +- .../with-vercel-website/src/environment.d.ts | 2 +- .../fixtures/payload-configs/minimal.ts | 2 +- .../payload-configs/multiple-buildconfig.ts | 2 +- .../payload-configs/postgres-adapter.ts | 2 +- .../fixtures/payload-configs/with-alias.ts | 2 +- .../payload-configs/with-other-imports.ts | 2 +- .../fixtures/payload-configs/with-storage.ts | 2 +- test/dev.ts | 14 +- test/generateDatabaseAdapter.ts | 37 ++-- .../db/mongodb-atlas/docker-compose.yml | 35 ++++ .../db/mongodb-atlas/run-test-connection.ts | 13 ++ .../db/mongodb/docker-compose-entrypoint.sh | 127 ++++++++++++ test/helpers/db/mongodb/docker-compose.yml | 80 ++++++++ test/helpers/db/mongodb/keyfile | 1 + test/helpers/db/mongodb/mongot-config.yml | 19 ++ test/helpers/db/mongodb/passwordFile | 1 + .../helpers/db/mongodb/run-test-connection.ts | 13 ++ test/helpers/db/mongodb/test-connection.ts | 183 ++++++++++++++++++ test/helpers/db/postgres/docker-compose.yml | 41 ++++ test/helpers/startMemoryDB.ts | 53 ----- test/helpers/stopMemoryDB.ts | 36 ---- test/jest.config.js | 3 - test/plugin-cloud-storage/.env.emulated | 1 - test/storage-s3/.env.emulated | 32 --- tools/claude-plugin/skills/payload/SKILL.md | 2 +- .../skills/payload/reference/ADAPTERS.md | 4 +- .../payload/reference/PLUGIN-DEVELOPMENT.md | 4 +- .../src/build-template-with-local-pkgs.ts | 2 +- .../src/generate-template-variations.ts | 22 +-- 135 files changed, 915 insertions(+), 443 deletions(-) create mode 100644 .env.example create mode 100644 .github/actions/start-database/action.yml create mode 100644 test/helpers/db/mongodb-atlas/docker-compose.yml create mode 100644 test/helpers/db/mongodb-atlas/run-test-connection.ts create mode 100755 test/helpers/db/mongodb/docker-compose-entrypoint.sh create mode 100644 test/helpers/db/mongodb/docker-compose.yml create mode 100644 test/helpers/db/mongodb/keyfile create mode 100644 test/helpers/db/mongodb/mongot-config.yml create mode 100644 test/helpers/db/mongodb/passwordFile create mode 100644 test/helpers/db/mongodb/run-test-connection.ts create mode 100644 test/helpers/db/mongodb/test-connection.ts create mode 100644 test/helpers/db/postgres/docker-compose.yml delete mode 100644 test/helpers/startMemoryDB.ts delete mode 100644 test/helpers/stopMemoryDB.ts delete mode 100644 test/storage-s3/.env.emulated diff --git a/.env.example b/.env.example new file mode 100644 index 00000000000..57137813bbd --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +# Database adapters: mongodb, mongodb-atlas, cosmosdb, documentdb, firestore, postgres, postgres-custom-schema, postgres-uuid, postgres-read-replica, vercel-postgres-read-replica, sqlite, sqlite-uuid, supabase, d1 +PAYLOAD_DATABASE=mongodb + +# Optional - used for the `translateNewKeys` script +OPENAI_KEY= diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 7e8bb9fe0c8..ba1681a012e 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -9,10 +9,10 @@ inputs: description: Pnpm version override pnpm-run-install: description: Whether to run pnpm install - default: true + default: 'true' pnpm-restore-cache: description: Whether to restore cache - default: true + default: 'true' pnpm-install-cache-key: description: The cache key override for the pnpm install cache diff --git a/.github/actions/start-database/action.yml b/.github/actions/start-database/action.yml new file mode 100644 index 00000000000..1698aab39b7 --- /dev/null +++ b/.github/actions/start-database/action.yml @@ -0,0 +1,65 @@ +name: Start Database +description: Starts the required database for tests + +inputs: + database: + description: 'Database type: mongodb, mongodb-atlas, cosmosdb, documentdb, firestore, postgres, postgres-custom-schema, postgres-uuid, postgres-read-replica, vercel-postgres-read-replica, sqlite, sqlite-uuid, supabase, d1' + required: true + +outputs: + POSTGRES_URL: + description: PostgreSQL connection URL + value: ${{ steps.postgres.outputs.url }} + MONGODB_URL: + description: MongoDB connection URL + value: ${{ steps.mongodb.outputs.url }} + MONGODB_ATLAS_URL: + description: MongoDB Atlas connection URL + value: ${{ steps.mongodb-atlas.outputs.url }} + +runs: + using: composite + steps: + - name: Start MongoDB + id: mongodb + if: contains(fromJSON('["mongodb", "cosmosdb", "documentdb", "firestore"]'), inputs.database) + shell: bash + run: | + docker compose -f test/helpers/db/mongodb/docker-compose.yml up -d --wait + echo "url=mongodb://payload:payload@localhost:27017/payload?authSource=admin&directConnection=true&replicaSet=rs0" >> $GITHUB_OUTPUT + + - name: Start MongoDB Atlas Local + id: mongodb-atlas + if: inputs.database == 'mongodb-atlas' + shell: bash + run: | + docker compose -f test/helpers/db/mongodb-atlas/docker-compose.yml up -d --wait + echo "url=mongodb://localhost:27018/payload?directConnection=true&replicaSet=mongodb-atlas-local" >> $GITHUB_OUTPUT + + - name: Start PostgreSQL + id: postgres + if: startsWith(inputs.database, 'postgres') + shell: bash + run: | + docker compose -f test/helpers/db/postgres/docker-compose.yml up -d --wait + echo "url=postgresql://payload:payload@localhost:5433/payload" >> $GITHUB_OUTPUT + + - name: Configure PostgreSQL custom schema + if: inputs.database == 'postgres-custom-schema' + shell: bash + run: | + docker exec postgres-payload-test psql -U payload -d payload -c "CREATE SCHEMA custom;" + + - name: Start Supabase + id: supabase + if: inputs.database == 'supabase' + uses: supabase/setup-cli@v1 + with: + version: latest + + - name: Initialize Supabase + if: inputs.database == 'supabase' + shell: bash + run: | + supabase init + supabase start diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 330087571a0..b17a14d8660 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,13 +2,10 @@ name: ci on: pull_request: - types: - - opened - - reopened - - synchronize + types: [opened, reopened, synchronize] + push: - branches: - - main + branches: [main] concurrency: # -- @@ -53,7 +50,7 @@ jobs: - 'package.json' templates: - 'templates/**' - - name: Log all filter results + - name: Log filter results run: | echo "needs_build: ${{ steps.filter.outputs.needs_build }}" echo "needs_tests: ${{ steps.filter.outputs.needs_tests }}" @@ -74,7 +71,7 @@ jobs: build: needs: changes - if: ${{ needs.changes.outputs.needs_build == 'true' }} + if: needs.changes.outputs.needs_build == 'true' runs-on: ubuntu-24.04 steps: @@ -96,7 +93,7 @@ jobs: tests-unit: runs-on: ubuntu-24.04 needs: [changes, build] - if: ${{ needs.changes.outputs.needs_tests == 'true' }} + if: needs.changes.outputs.needs_tests == 'true' steps: - uses: actions/checkout@v5 @@ -120,7 +117,7 @@ jobs: tests-types: runs-on: ubuntu-24.04 needs: [changes, build] - if: ${{ needs.changes.outputs.needs_tests == 'true' }} + if: needs.changes.outputs.needs_tests == 'true' steps: - uses: actions/checkout@v5 @@ -144,7 +141,7 @@ jobs: tests-int: runs-on: ubuntu-24.04 needs: [changes, build] - if: ${{ needs.changes.outputs.needs_tests == 'true' }} + if: needs.changes.outputs.needs_tests == 'true' name: int-${{ matrix.database }} timeout-minutes: 45 strategy: @@ -152,6 +149,7 @@ jobs: matrix: database: - mongodb + - mongodb-atlas - documentdb - cosmosdb - firestore @@ -163,28 +161,12 @@ jobs: - sqlite-uuid env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: payloadtests AWS_ENDPOINT_URL: http://127.0.0.1:4566 AWS_ACCESS_KEY_ID: localstack AWS_SECRET_ACCESS_KEY: localstack AWS_REGION: us-east-1 services: - postgres: - # Custom postgres 17 docker image that supports both pg-vector and postgis: https://github.com/payloadcms/postgis-vector - image: ${{ (startsWith(matrix.database, 'postgres') ) && 'ghcr.io/payloadcms/postgis-vector:latest' || '' }} - env: - # must specify password for PG Docker container image, see: https://registry.hub.docker.com/_/postgres?tab=description&page=1&name=10 - POSTGRES_USER: ${{ env.POSTGRES_USER }} - POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }} - POSTGRES_DB: ${{ env.POSTGRES_DB }} - ports: - - 5432:5432 - # needed because the postgres container does not provide a healthcheck - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - redis: image: redis:latest ports: @@ -210,50 +192,29 @@ jobs: - name: Start LocalStack run: pnpm docker:start - - name: Install Supabase CLI - uses: supabase/setup-cli@v1 - with: - version: latest - if: matrix.database == 'supabase' - - - name: Initialize Supabase - run: | - supabase init - supabase start - if: matrix.database == 'supabase' - - - name: Configure PostgreSQL - run: | - psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE ROLE runner SUPERUSER LOGIN;" - psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "SELECT version();" - echo "POSTGRES_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV - if: startsWith(matrix.database, 'postgres') - - - name: Configure PostgreSQL with custom schema - run: | - psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE SCHEMA custom;" - if: matrix.database == 'postgres-custom-schema' - - - name: Configure Supabase - run: | - echo "POSTGRES_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres" >> $GITHUB_ENV - if: matrix.database == 'supabase' - - name: Configure Redis run: | - echo "REDIS_URL=redis://127.0.0.1:6379" >> $GITHUB_ENV + echo "REDIS_URL=redis://127.0.0.1:6379" >> $GITHUB_ENV + + - name: Start database + id: db + uses: ./.github/actions/start-database + with: + database: ${{ matrix.database }} - name: Integration Tests run: pnpm test:int env: NODE_OPTIONS: --max-old-space-size=8096 PAYLOAD_DATABASE: ${{ matrix.database }} - POSTGRES_URL: ${{ env.POSTGRES_URL }} + POSTGRES_URL: ${{ steps.db.outputs.POSTGRES_URL }} + MONGODB_URL: ${{ steps.db.outputs.MONGODB_URL }} + MONGODB_ATLAS_URL: ${{ steps.db.outputs.MONGODB_ATLAS_URL }} tests-e2e: runs-on: ubuntu-24.04 needs: [changes, build] - if: ${{ needs.changes.outputs.needs_tests == 'true' }} + if: needs.changes.outputs.needs_tests == 'true' name: e2e-${{ matrix.suite }} timeout-minutes: 45 strategy: @@ -349,7 +310,13 @@ jobs: - name: Start LocalStack run: pnpm docker:start - if: ${{ matrix.suite == 'plugin-cloud-storage' }} + if: matrix.suite == 'plugin-cloud-storage' + + - name: Start database + id: db + uses: ./.github/actions/start-database + with: + database: mongodb - name: Store Playwright's Version run: | @@ -493,7 +460,7 @@ jobs: - name: Start LocalStack run: pnpm docker:start - if: ${{ matrix.suite == 'plugin-cloud-storage' }} + if: matrix.suite == 'plugin-cloud-storage' - name: Store Playwright's Version run: | @@ -542,7 +509,7 @@ jobs: build-and-test-templates: runs-on: ubuntu-24.04 needs: [changes, build] - if: ${{ needs.changes.outputs.needs_build == 'true' }} + if: needs.changes.outputs.needs_build == 'true' name: build-template-${{ matrix.template }}-${{ matrix.database }} strategy: fail-fast: false @@ -613,7 +580,8 @@ jobs: # Avoid dockerhub rate-limiting - name: Cache Docker images - uses: ScribeMD/docker-cache@0.5.0 + # Use AndreKurait/docker-cache@0.6.0 instead of ScribeMD/docker-cache@0.5.0 to fix the following issue: https://github.com/ScribeMD/docker-cache/issues/837 ("Warning: Failed to restore: Cache service responded with 400") + uses: AndreKurait/docker-cache@0.6.0 with: key: docker-${{ runner.os }}-mongo-${{ env.MONGODB_VERSION }} @@ -672,7 +640,7 @@ jobs: tests-type-generation: runs-on: ubuntu-24.04 needs: [changes, build] - if: ${{ needs.changes.outputs.needs_tests == 'true' }} + if: needs.changes.outputs.needs_tests == 'true' steps: - uses: actions/checkout@v5 @@ -699,14 +667,16 @@ jobs: if: always() runs-on: ubuntu-24.04 needs: - - lint - - build - - build-and-test-templates - - tests-unit - - tests-int - - tests-e2e - - tests-types - - tests-type-generation + [ + lint, + build, + build-and-test-templates, + tests-unit, + tests-int, + tests-e2e, + tests-types, + tests-type-generation, + ] steps: - if: ${{ always() && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }} diff --git a/.github/workflows/post-release-templates.yml b/.github/workflows/post-release-templates.yml index a5eae231136..9998114d18c 100644 --- a/.github/workflows/post-release-templates.yml +++ b/.github/workflows/post-release-templates.yml @@ -62,7 +62,7 @@ jobs: - name: Start PostgreSQL uses: CasperWA/postgresql-action@v1.2 with: - postgresql version: '14' # See https://hub.docker.com/_/postgres for available versions + postgresql version: "14" # See https://hub.docker.com/_/postgres for available versions postgresql db: ${{ env.POSTGRES_DB }} postgresql user: ${{ env.POSTGRES_USER }} postgresql password: ${{ env.POSTGRES_PASSWORD }} @@ -75,7 +75,7 @@ jobs: psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE ROLE runner SUPERUSER LOGIN;" psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "SELECT version();" echo "POSTGRES_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV - echo "DATABASE_URI=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV + echo "DATABASE_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV - name: Start MongoDB uses: supercharge/mongodb-github-action@1.12.0 @@ -108,13 +108,13 @@ jobs: uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GH_TOKEN_POST_RELEASE_TEMPLATES }} - labels: 'area: templates' + labels: "area: templates" author: github-actions[bot] - commit-message: 'templates: bump templates for ${{ needs.wait_for_release.outputs.release_tag }}' + commit-message: "templates: bump templates for ${{ needs.wait_for_release.outputs.release_tag }}" branch: ${{ steps.commit.outputs.branch }} base: main assignees: ${{ github.actor }} - title: 'templates: bump for ${{ needs.wait_for_release.outputs.release_tag }}' + title: "templates: bump for ${{ needs.wait_for_release.outputs.release_tag }}" body: | 🤖 Automated bump of templates for ${{ needs.wait_for_release.outputs.release_tag }} diff --git a/CLAUDE.md b/CLAUDE.md index 23ee9ff1b0e..22cd289ee5f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -72,7 +72,6 @@ Payload is a monorepo structured around Next.js, containing the core CMS platfor - `pnpm run dev` - Start dev server with default config (`test/_community/config.ts`) - `pnpm run dev ` - Start dev server with specific test config (e.g. `pnpm run dev fields` loads `test/fields/config.ts`) - `pnpm run dev:postgres` - Run dev server with Postgres -- `pnpm run dev:memorydb` - Run dev server with in-memory MongoDB ### Development Environment diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0a1bf17efc..c25ba0cbc88 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,11 +32,11 @@ To help us work on new features, you can create a new feature request post in [G ### Installation & Requirements -Payload is structured as a Monorepo, encompassing not only the core Payload platform but also various plugins and packages. To install all required dependencies, you have to run `pnpm install` once in the root directory. **PNPM IS REQUIRED!** Yarn or npm will not work - you will have to use pnpm to develop in the core repository. In most systems, the easiest way to install pnpm is to run `corepack enable` in your terminal. +Payload is structured as a Monorepo, encompassing not only the core Payload platform but also various plugins and packages. To install all required dependencies, you have to run `pnpm install` once in the root directory. **PNPM IS REQUIRED!** Yarn or npm will not work - you will have to use pnpm to develop in the core repository. In most systems, the easiest way to install pnpm is to run `npm add -g pnpm` in your terminal. -If you're coming from a very outdated version of payload, it is recommended to nuke the node_modules folder before running pnpm install. On UNIX systems, you can easily do that using the `pnpm clean:unix` command, which will delete all node_modules folders and build artefacts. +If you're coming from a very outdated version of payload, it is recommended to perform a clean install, which nukes the node_modules folder and reinstalls all dependencies. You can easily do that using the `pnpm reinstall` command. -It is also recommended to use at least Node v18 or higher. You can check your current node version by typing `node --version` in your terminal. The easiest way to switch between different node versions is to use [nvm](https://github.com/nvm-sh/nvm#intro). +It is also recommended to use at least Node v23.11.0 or higher. You can check your current node version by typing `node --version` in your terminal. The easiest way to switch between different node versions is to use [nvm](https://github.com/nvm-sh/nvm#intro). ### Code @@ -67,19 +67,67 @@ By default, payload will [automatically log you in](https://payloadcms.com/docs/ The default credentials are `dev@payloadcms.com` as E-Mail and `test` as password. These are used in the auto-login. -### Testing with your own MongoDB database +### Database Setup -If you wish to use your own MongoDB database for the `test` directory instead of using the in memory database, all you need to do is add the following env vars to the `test/dev.ts` file: +First, copy the `.env.example` file to your `.env`. -- `process.env.NODE_ENV` -- `process.env.PAYLOAD_TEST_MONGO_URL` -- Simply set `process.env.NODE_ENV` to `test` and set `process.env.PAYLOAD_TEST_MONGO_URL` to your MongoDB URL e.g. `mongodb://127.0.0.1/your-test-db`. +Set `PAYLOAD_DATABASE` in your `.env` file to choose the database adapter: -### Using Postgres +- `mongodb` - MongoDB Community with vector search (mongot) +- `mongodb-atlas` - MongoDB Atlas Local (all-in-one container) +- `cosmosdb` - MongoDB with compatibility options for Cosmos DB +- `documentdb` - MongoDB with compatibility options for Document DB +- `firestore` - MongoDB with compatibility options for Firestore +- `postgres` - PostgreSQL with pgvector and PostGIS +- `postgres-custom-schema` - PostgreSQL with custom schema +- `postgres-uuid` - PostgreSQL with UUID primary keys +- `postgres-read-replica` - PostgreSQL with read replica +- `sqlite` - SQLite +- `sqlite-uuid` - SQLite with UUID primary keys +- `supabase` - Supabase (PostgreSQL) +- `d1` - D1 (SQLite) -If you have postgres installed on your system, you can also run the test suites using postgres. By default, mongodb is used. +Then use Docker to start your database: -To do that, simply set the `PAYLOAD_DATABASE` environment variable to `postgres`. +### PostgreSQL + +```bash +pnpm docker:postgres:start # Start (persists data) +pnpm docker:postgres:restart:clean # Start fresh (removes data) +pnpm docker:postgres:stop # Stop +``` + +URL: `postgres://payload:payload@127.0.0.1:5433/payload` + +### MongoDB (with vector search) + +```bash +pnpm docker:mongodb:start # Start (persists data) +pnpm docker:mongodb:restart:clean # Start fresh (removes data) +pnpm docker:mongodb:stop # Stop +``` + +URL: `mongodb://payload:payload@localhost:27017/payload?authSource=admin&directConnection=true&replicaSet=rs0` + +### MongoDB Atlas Local + +```bash +pnpm docker:mongodb-atlas:start # Start (persists data) +pnpm docker:mongodb-atlas:restart:clean # Start fresh (removes data) +pnpm docker:mongodb-atlas:stop # Stop +``` + +URL: `mongodb://localhost:27018/payload?directConnection=true&replicaSet=mongodb-atlas-local` (no auth required) + +### SQLite + +SQLite databases don't require Docker - they're stored as files in the project. + +### Testing with your own database + +If you wish to use your own MongoDB database for the `test` directory instead of using the docker database, all you need to do is add the following env variable to your `.env` file: + +- `DATABASE_URL` to your database URL e.g. `mongodb://127.0.0.1/your-test-db`. ### Running the e2e and int tests @@ -120,10 +168,7 @@ This is how you can preview changes you made locally to the docs: 1. Clone our [website repository](https://github.com/payloadcms/website) 2. Run `pnpm install` -3. Duplicate the `.env.example` file and rename it to `.env` -4. Add a `DOCS_DIR` environment variable to the `.env` file which points to the absolute path of your modified docs folder. For example `DOCS_DIR=/Users/yourname/Documents/GitHub/payload/docs` -5. Run `pnpm fetchDocs:local`. If this was successful, you should see no error messages and the following output: _Docs successfully written to /.../website/src/app/docs.json_. There could be error messages if you have incorrect markdown in your local docs folder. In this case, it will tell you how you can fix it -6. You're done! Now you can start the website locally using `pnpm dev` and preview the docs under [http://localhost:3000/docs/local](http://localhost:3000/docs/local) +3. Follow the instructions in the [README of the website repository](https://github.com/payloadcms/website/blob/main/README.md#documentation) to preview the docs locally. ## Internationalization (i18n) diff --git a/docs/configuration/environment-vars.mdx b/docs/configuration/environment-vars.mdx index c73d1ae523f..1361ae9ea20 100644 --- a/docs/configuration/environment-vars.mdx +++ b/docs/configuration/environment-vars.mdx @@ -24,7 +24,7 @@ Here is an example of what an `.env` file might look like: ```plaintext SERVER_URL=localhost:3000 -DATABASE_URI=mongodb://localhost:27017/my-database +DATABASE_URL=mongodb://localhost:27017/my-database ``` To use Environment Variables in your Payload Config, you can access them directly from `process.env`: diff --git a/docs/configuration/overview.mdx b/docs/configuration/overview.mdx index dd697723cd6..f08f428b45a 100644 --- a/docs/configuration/overview.mdx +++ b/docs/configuration/overview.mdx @@ -40,7 +40,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ secret: process.env.PAYLOAD_SECRET, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), collections: [ { diff --git a/docs/database/mongodb.mdx b/docs/database/mongodb.mdx index 15482096356..4ca47bc7d2a 100644 --- a/docs/database/mongodb.mdx +++ b/docs/database/mongodb.mdx @@ -23,7 +23,7 @@ export default buildConfig({ db: mongooseAdapter({ // Mongoose-specific arguments go here. // URL is required. - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -67,7 +67,7 @@ import { mongooseAdapter, compatibilityOptions } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, // For example, if you're using firestore: ...compatibilityOptions.firestore, }), @@ -99,7 +99,7 @@ export default buildConfig({ db: mongooseAdapter({ // Mongoose-specific arguments go here. // URL is required. - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, collation: { // Set any MongoDB collation options here. // The locale will be set automatically based on the request locale. diff --git a/docs/database/overview.mdx b/docs/database/overview.mdx index c808399542d..fdd354baa1e 100644 --- a/docs/database/overview.mdx +++ b/docs/database/overview.mdx @@ -24,7 +24,7 @@ export default buildConfig({ // ... // highlight-start db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), // highlight-end }) diff --git a/docs/database/postgres.mdx b/docs/database/postgres.mdx index 3f2c8c1382e..3ba4d829757 100644 --- a/docs/database/postgres.mdx +++ b/docs/database/postgres.mdx @@ -27,7 +27,7 @@ export default buildConfig({ // Postgres-specific arguments go here. // `pool` is required. pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, }), }) diff --git a/docs/getting-started/installation.mdx b/docs/getting-started/installation.mdx index 27129d3e891..48dbdf3fea8 100644 --- a/docs/getting-started/installation.mdx +++ b/docs/getting-started/installation.mdx @@ -164,7 +164,7 @@ export default buildConfig({ // Whichever Database Adapter you're using should go here // Mongoose is shown as an example, but you can also use Postgres db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), // If you want to resize images, crop, set focal point, etc. // make sure to install it and pass it to the config. diff --git a/docs/production/deployment.mdx b/docs/production/deployment.mdx index 35cdd2e7c3a..f80b6554743 100644 --- a/docs/production/deployment.mdx +++ b/docs/production/deployment.mdx @@ -72,7 +72,7 @@ more. [Click here to learn more](/docs/production/preventing-abuse). Payload can be used with any Postgres database or MongoDB-compatible database including AWS DocumentDB or Azure Cosmos DB. Make sure your production environment has access to the database that Payload uses. -Out of the box, Payload templates pass the `process.env.DATABASE_URI` environment variable to its database adapters, so make sure you've got that environment variable (and all others that you use) assigned in your deployment platform. +Out of the box, Payload templates pass the `process.env.DATABASE_URL` environment variable to its database adapters, so make sure you've got that environment variable (and all others that you use) assigned in your deployment platform. ### DocumentDB @@ -140,7 +140,7 @@ Follow the docs to configure any one of these storage providers. For local devel ## Docker This is an example of a multi-stage docker build of Payload for production. Ensure you are setting your environment -variables on deployment, like `PAYLOAD_SECRET`, `PAYLOAD_CONFIG_PATH`, and `DATABASE_URI` if needed. If you don't want to have a DB connection and your build requires that, learn [here](./building-without-a-db-connection) how to prevent that. +variables on deployment, like `PAYLOAD_SECRET`, `PAYLOAD_CONFIG_PATH`, and `DATABASE_URL` if needed. If you don't want to have a DB connection and your build requires that, learn [here](./building-without-a-db-connection) how to prevent that. In your Next.js config, set the `output` property `standalone`. @@ -249,7 +249,7 @@ services: env_file: - .env - # Ensure your DATABASE_URI uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name + # Ensure your DATABASE_URL uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name mongo: image: mongo:latest ports: diff --git a/examples/astro/payload/.env.example b/examples/astro/payload/.env.example index 441b33e686e..9670f5dd8c0 100644 --- a/examples/astro/payload/.env.example +++ b/examples/astro/payload/.env.example @@ -1,2 +1,2 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-template-blank-3-0 +DATABASE_URL=mongodb://127.0.0.1/payload-template-blank-3-0 PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/examples/astro/payload/docker-compose.yml b/examples/astro/payload/docker-compose.yml index 3aba7cc7e2a..4ed0d24c9ae 100644 --- a/examples/astro/payload/docker-compose.yml +++ b/examples/astro/payload/docker-compose.yml @@ -1,10 +1,10 @@ -version: '3' +version: "3" services: payload: image: node:18-alpine ports: - - '3000:3000' + - "3000:3000" volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -16,11 +16,11 @@ services: env_file: - .env - # Ensure your DATABASE_URI uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name + # Ensure your DATABASE_URL uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name mongo: image: mongo:latest ports: - - '27017:27017' + - "27017:27017" command: - --storageEngine=wiredTiger volumes: diff --git a/examples/astro/payload/src/payload.config.ts b/examples/astro/payload/src/payload.config.ts index 818f99470be..07114cd983f 100644 --- a/examples/astro/payload/src/payload.config.ts +++ b/examples/astro/payload/src/payload.config.ts @@ -46,7 +46,7 @@ export default buildConfig({ } }, db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), sharp, plugins: [], diff --git a/examples/astro/website/.env.example b/examples/astro/website/.env.example index 441b33e686e..9670f5dd8c0 100644 --- a/examples/astro/website/.env.example +++ b/examples/astro/website/.env.example @@ -1,2 +1,2 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-template-blank-3-0 +DATABASE_URL=mongodb://127.0.0.1/payload-template-blank-3-0 PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/examples/auth/.env.example b/examples/auth/.env.example index 23a57a3dcef..bb7e07464aa 100644 --- a/examples/auth/.env.example +++ b/examples/auth/.env.example @@ -1,5 +1,5 @@ # Database connection string -DATABASE_URI=mongodb://127.0.0.1/payload-draft-preview-example +DATABASE_URL=mongodb://127.0.0.1/payload-draft-preview-example # Used to encrypt JWT tokens PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/examples/auth/src/payload.config.ts b/examples/auth/src/payload.config.ts index e6f1a51cae7..ba1ecb9d2d8 100644 --- a/examples/auth/src/payload.config.ts +++ b/examples/auth/src/payload.config.ts @@ -18,7 +18,7 @@ export default buildConfig({ cors: [process.env.NEXT_PUBLIC_SERVER_URL || ''].filter(Boolean), csrf: [process.env.NEXT_PUBLIC_SERVER_URL || ''].filter(Boolean), db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), editor: slateEditor({}), secret: process.env.PAYLOAD_SECRET || '', diff --git a/examples/custom-components/.env.example b/examples/custom-components/.env.example index 2f41889fd77..2d1aece3ef2 100644 --- a/examples/custom-components/.env.example +++ b/examples/custom-components/.env.example @@ -1,3 +1,3 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-example-custom-fields +DATABASE_URL=mongodb://127.0.0.1/payload-example-custom-fields PAYLOAD_SECRET=PAYLOAD_CUSTOM_FIELDS_EXAMPLE_SECRET_KEY PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000 diff --git a/examples/custom-components/src/payload.config.ts b/examples/custom-components/src/payload.config.ts index c12f56c0882..b7cf55403bb 100644 --- a/examples/custom-components/src/payload.config.ts +++ b/examples/custom-components/src/payload.config.ts @@ -41,7 +41,7 @@ export default buildConfig({ }, collections: [CustomFields, CustomViews, CustomRootViews], db: mongooseAdapter({ - url: process.env.DATABASE_URI as string, + url: process.env.DATABASE_URL as string, }), editor: lexicalEditor({}), graphQL: { diff --git a/examples/custom-server/src/payload.config.ts b/examples/custom-server/src/payload.config.ts index f64245a20a9..ff31b9677b2 100644 --- a/examples/custom-server/src/payload.config.ts +++ b/examples/custom-server/src/payload.config.ts @@ -24,7 +24,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), plugins: [], }) diff --git a/examples/draft-preview/.env.example b/examples/draft-preview/.env.example index 8ed3f4ed9ef..dc03e642373 100644 --- a/examples/draft-preview/.env.example +++ b/examples/draft-preview/.env.example @@ -1,5 +1,5 @@ # Database connection string -DATABASE_URI=mongodb://127.0.0.1/payload-draft-preview-example +DATABASE_URL=mongodb://127.0.0.1/payload-draft-preview-example # Used to encrypt JWT tokens PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/examples/draft-preview/src/payload.config.ts b/examples/draft-preview/src/payload.config.ts index 8edade0f4a6..94ecc357b1c 100644 --- a/examples/draft-preview/src/payload.config.ts +++ b/examples/draft-preview/src/payload.config.ts @@ -22,7 +22,7 @@ export default buildConfig({ cors: [process.env.NEXT_PUBLIC_SERVER_URL || ''].filter(Boolean), csrf: [process.env.NEXT_PUBLIC_SERVER_URL || ''].filter(Boolean), db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), editor: slateEditor({}), globals: [MainMenu], diff --git a/examples/email/.env.example b/examples/email/.env.example index dd935c4aaaa..797a8fa308b 100644 --- a/examples/email/.env.example +++ b/examples/email/.env.example @@ -1,4 +1,4 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-example-email +DATABASE_URL=mongodb://127.0.0.1/payload-example-email NODE_ENV=development PAYLOAD_SECRET=PAYLOAD_EMAIL_EXAMPLE_SECRET_KEY PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000 diff --git a/examples/email/src/payload.config.ts b/examples/email/src/payload.config.ts index 55f1c7eaa1c..7cb71c0f18d 100644 --- a/examples/email/src/payload.config.ts +++ b/examples/email/src/payload.config.ts @@ -21,7 +21,7 @@ export default buildConfig({ }, collections: [Newsletter, Users], db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), editor: lexicalEditor({}), // For example use case, we are passing nothing to nodemailerAdapter diff --git a/examples/form-builder/.env.example b/examples/form-builder/.env.example index 80e496fd06d..6efe4c54d4a 100644 --- a/examples/form-builder/.env.example +++ b/examples/form-builder/.env.example @@ -1,3 +1,3 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-form-builder-example +DATABASE_URL=mongodb://127.0.0.1/payload-form-builder-example PAYLOAD_SECRET=YOUR_SECRET_HERE NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000 diff --git a/examples/form-builder/src/payload.config.ts b/examples/form-builder/src/payload.config.ts index 03b3649cd2d..4962bc48d0d 100644 --- a/examples/form-builder/src/payload.config.ts +++ b/examples/form-builder/src/payload.config.ts @@ -32,7 +32,7 @@ export default buildConfig({ // We need to set CORS rules pointing to our hosted domains for the frontend to be able to submit to our API cors: [process.env.NEXT_PUBLIC_PAYLOAD_URL || ''], db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), editor: lexicalEditor({ features: () => { diff --git a/examples/live-preview/.env.example b/examples/live-preview/.env.example index c8f8ecd3b20..5999abc0760 100644 --- a/examples/live-preview/.env.example +++ b/examples/live-preview/.env.example @@ -1,3 +1,3 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-example-live-preview +DATABASE_URL=mongodb://127.0.0.1/payload-example-live-preview PAYLOAD_SECRET=ENTER-STRING-HERE NEXT_PUBLIC_SERVER_URL=http://localhost:3000 diff --git a/examples/live-preview/src/payload.config.ts b/examples/live-preview/src/payload.config.ts index 84a18d4db37..99eea9077a6 100644 --- a/examples/live-preview/src/payload.config.ts +++ b/examples/live-preview/src/payload.config.ts @@ -27,7 +27,7 @@ export default buildConfig({ }, collections: [Pages, Users], db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), editor: slateEditor({}), globals: [MainMenu], diff --git a/examples/localization/.env.example b/examples/localization/.env.example index dd13db6e198..d7a6c70be28 100644 --- a/examples/localization/.env.example +++ b/examples/localization/.env.example @@ -1,5 +1,5 @@ # Database connection string -DATABASE_URI=mongodb://127.0.0.1/payload-template-website +DATABASE_URL=mongodb://127.0.0.1/payload-template-website # Used to encrypt JWT tokens PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/examples/localization/src/payload.config.ts b/examples/localization/src/payload.config.ts index 381f2bb82f0..b00ef6ea78d 100644 --- a/examples/localization/src/payload.config.ts +++ b/examples/localization/src/payload.config.ts @@ -123,7 +123,7 @@ export default buildConfig({ }, }), db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), collections: [Pages, Posts, Media, Categories, Users], cors: [process.env.PAYLOAD_PUBLIC_SERVER_URL || ''].filter(Boolean), diff --git a/examples/multi-tenant/.env.example b/examples/multi-tenant/.env.example index 56d50a07d32..b2f4ad5b087 100644 --- a/examples/multi-tenant/.env.example +++ b/examples/multi-tenant/.env.example @@ -1,5 +1,5 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-example-multi-tenant +DATABASE_URL=mongodb://127.0.0.1/payload-example-multi-tenant POSTGRES_URL=postgres://127.0.0.1:5432/payload-example-multi-tenant PAYLOAD_SECRET=PAYLOAD_MULTI_TENANT_EXAMPLE_SECRET_KEY PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000 -SEED_DB=true \ No newline at end of file +SEED_DB=true diff --git a/examples/multi-tenant/src/payload.config.ts b/examples/multi-tenant/src/payload.config.ts index 9d464800ce8..70dd60c0536 100644 --- a/examples/multi-tenant/src/payload.config.ts +++ b/examples/multi-tenant/src/payload.config.ts @@ -24,7 +24,7 @@ export default buildConfig({ }, collections: [Pages, Users, Tenants], // db: mongooseAdapter({ - // url: process.env.DATABASE_URI as string, + // url: process.env.DATABASE_URL as string, // }), db: postgresAdapter({ pool: { diff --git a/examples/remix/payload/.env.example b/examples/remix/payload/.env.example index 441b33e686e..9670f5dd8c0 100644 --- a/examples/remix/payload/.env.example +++ b/examples/remix/payload/.env.example @@ -1,2 +1,2 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-template-blank-3-0 +DATABASE_URL=mongodb://127.0.0.1/payload-template-blank-3-0 PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/examples/remix/payload/docker-compose.yml b/examples/remix/payload/docker-compose.yml index 3aba7cc7e2a..4ed0d24c9ae 100644 --- a/examples/remix/payload/docker-compose.yml +++ b/examples/remix/payload/docker-compose.yml @@ -1,10 +1,10 @@ -version: '3' +version: "3" services: payload: image: node:18-alpine ports: - - '3000:3000' + - "3000:3000" volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -16,11 +16,11 @@ services: env_file: - .env - # Ensure your DATABASE_URI uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name + # Ensure your DATABASE_URL uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name mongo: image: mongo:latest ports: - - '27017:27017' + - "27017:27017" command: - --storageEngine=wiredTiger volumes: diff --git a/examples/remix/payload/src/payload.config.ts b/examples/remix/payload/src/payload.config.ts index 818f99470be..07114cd983f 100644 --- a/examples/remix/payload/src/payload.config.ts +++ b/examples/remix/payload/src/payload.config.ts @@ -46,7 +46,7 @@ export default buildConfig({ } }, db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), sharp, plugins: [], diff --git a/examples/remix/website/.env.example b/examples/remix/website/.env.example index 441b33e686e..9670f5dd8c0 100644 --- a/examples/remix/website/.env.example +++ b/examples/remix/website/.env.example @@ -1,2 +1,2 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-template-blank-3-0 +DATABASE_URL=mongodb://127.0.0.1/payload-template-blank-3-0 PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/examples/tailwind-shadcn-ui/.env.example b/examples/tailwind-shadcn-ui/.env.example index 441b33e686e..9670f5dd8c0 100644 --- a/examples/tailwind-shadcn-ui/.env.example +++ b/examples/tailwind-shadcn-ui/.env.example @@ -1,2 +1,2 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-template-blank-3-0 +DATABASE_URL=mongodb://127.0.0.1/payload-template-blank-3-0 PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/examples/tailwind-shadcn-ui/src/payload.config.ts b/examples/tailwind-shadcn-ui/src/payload.config.ts index a6a993a526b..d5307e28e20 100644 --- a/examples/tailwind-shadcn-ui/src/payload.config.ts +++ b/examples/tailwind-shadcn-ui/src/payload.config.ts @@ -21,6 +21,6 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), }) diff --git a/examples/whitelabel/.env.example b/examples/whitelabel/.env.example index 47d7a6e00fb..ce0c84ea899 100644 --- a/examples/whitelabel/.env.example +++ b/examples/whitelabel/.env.example @@ -1,3 +1,3 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-example-whitelabel +DATABASE_URL=mongodb://127.0.0.1/payload-example-whitelabel PAYLOAD_SECRET=PAYLOAD_WHITELABEL_EXAMPLE_SECRET_KEY PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000 diff --git a/examples/whitelabel/src/payload.config.ts b/examples/whitelabel/src/payload.config.ts index dc70b2ca036..daca351e4fb 100644 --- a/examples/whitelabel/src/payload.config.ts +++ b/examples/whitelabel/src/payload.config.ts @@ -45,7 +45,7 @@ export default buildConfig({ }, }, db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), editor: lexicalEditor({}), graphQL: { diff --git a/package.json b/package.json index 03b1dc879e3..27b27e398cb 100644 --- a/package.json +++ b/package.json @@ -77,12 +77,25 @@ "dev:generate-graphql-schema": "pnpm runts ./test/generateGraphQLSchema.ts", "dev:generate-importmap": "pnpm runts ./test/generateImportMap.ts", "dev:generate-types": "pnpm runts ./test/generateTypes.ts", - "dev:memorydb": "cross-env NODE_OPTIONS=--no-deprecation tsx ./test/dev.ts --start-memory-db", "dev:postgres": "cross-env PAYLOAD_DATABASE=postgres pnpm runts ./test/dev.ts", "dev:prod": "cross-env NODE_OPTIONS=--no-deprecation tsx ./test/dev.ts --prod", - "dev:prod:memorydb": "cross-env NODE_OPTIONS=--no-deprecation tsx ./test/dev.ts --prod --start-memory-db", "dev:vercel-postgres": "cross-env PAYLOAD_DATABASE=vercel-postgres pnpm runts ./test/dev.ts", "devsafe": "node ./scripts/delete-recursively.js '**/.next' && pnpm dev", + "docker:mongodb-atlas:restart": "pnpm docker:mongodb-atlas:stop && pnpm docker:mongodb-atlas:start", + "docker:mongodb-atlas:restart:clean": "docker rm -f mongodb-atlas-payload-test 2>/dev/null; docker compose -f test/helpers/db/mongodb-atlas/docker-compose.yml down -v && pnpm docker:mongodb-atlas:start", + "docker:mongodb-atlas:start": "docker compose -f test/helpers/db/mongodb-atlas/docker-compose.yml up -d --wait", + "docker:mongodb-atlas:stop": "docker compose -f test/helpers/db/mongodb-atlas/docker-compose.yml down", + "docker:mongodb-atlas:test": "pnpm runts test/helpers/db/mongodb-atlas/run-test-connection.ts", + "docker:mongodb:restart": "pnpm docker:mongodb:stop && pnpm docker:mongodb:start", + "docker:mongodb:restart:clean": "docker rm -f mongodb-payload-test mongot-payload-test 2>/dev/null; docker compose -f test/helpers/db/mongodb/docker-compose.yml down -v && pnpm docker:mongodb:start", + "docker:mongodb:start": "docker compose -f test/helpers/db/mongodb/docker-compose.yml up -d --wait", + "docker:mongodb:stop": "docker rm -f mongodb-payload-test mongot-payload-test 2>/dev/null; docker compose -f test/helpers/db/mongodb/docker-compose.yml down", + "docker:mongodb:test": "pnpm runts test/helpers/db/mongodb/run-test-connection.ts", + "docker:postgres:restart": "pnpm docker:postgres:stop && pnpm docker:postgres:start", + "docker:postgres:restart:clean": "docker rm -f postgres-payload-test 2>/dev/null; docker compose -f test/helpers/db/postgres/docker-compose.yml down -v && pnpm docker:postgres:start", + "docker:postgres:start": "docker compose -f test/helpers/db/postgres/docker-compose.yml up -d --wait", + "docker:postgres:start:clean": "docker pull ghcr.io/payloadcms/postgis-vector:latest && docker compose -f test/helpers/db/postgres/docker-compose.yml down -v && docker compose -f test/helpers/db/postgres/docker-compose.yml up -d --wait", + "docker:postgres:stop": "docker rm -f postgres-payload-test 2>/dev/null; docker compose -f test/helpers/db/postgres/docker-compose.yml down", "docker:restart": "pnpm docker:stop --remove-orphans && pnpm docker:start", "docker:start": "docker compose -f test/docker-compose.yml up -d", "docker:stop": "docker compose -f test/docker-compose.yml down", @@ -178,7 +191,6 @@ "jest": "29.7.0", "lint-staged": "15.2.7", "minimist": "1.2.8", - "mongodb-memory-server": "10.1.4", "mongoose": "8.15.1", "next": "15.4.10", "open": "^10.1.0", @@ -213,7 +225,6 @@ "cross-env": "$cross-env", "dotenv": "$dotenv", "graphql": "^16.8.1", - "mongodb-memory-server": "$mongodb-memory-server", "react": "$react", "react-dom": "$react-dom", "typescript": "$typescript" diff --git a/packages/create-payload-app/src/lib/ast/adapter-config.ts b/packages/create-payload-app/src/lib/ast/adapter-config.ts index 23f51bb72ad..08a908bd611 100644 --- a/packages/create-payload-app/src/lib/ast/adapter-config.ts +++ b/packages/create-payload-app/src/lib/ast/adapter-config.ts @@ -48,7 +48,7 @@ export const DB_ADAPTER_CONFIG: Record = adapterName: 'sqliteAdapter', configTemplate: () => `sqliteAdapter({ client: { - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }, })`, packageName: '@payloadcms/db-sqlite', diff --git a/packages/create-payload-app/src/lib/ast/payload-config.spec.ts b/packages/create-payload-app/src/lib/ast/payload-config.spec.ts index 2d45be8cd0c..7c443cfcf7a 100644 --- a/packages/create-payload-app/src/lib/ast/payload-config.spec.ts +++ b/packages/create-payload-app/src/lib/ast/payload-config.spec.ts @@ -141,7 +141,7 @@ export default buildConfig({ const result = addDatabaseAdapter({ sourceFile, adapter, - envVarName: 'DATABASE_URI', + envVarName: 'DATABASE_URL', }) expect(result.success).toBe(true) @@ -153,7 +153,7 @@ export default buildConfig({ new RegExp(`import.*${adapterName}.*from.*${packageName.replace('/', '\\/')}`), ) expect(text).toContain(`db: ${adapterName}`) - expect(text).toContain('process.env.DATABASE_URI') + expect(text).toContain('process.env.DATABASE_URL') }) it('replaces existing db adapter', () => { @@ -172,7 +172,7 @@ export default buildConfig({ const result = addDatabaseAdapter({ sourceFile, adapter: 'postgres', - envVarName: 'DATABASE_URI', + envVarName: 'DATABASE_URL', }) expect(result.success).toBe(true) @@ -410,7 +410,7 @@ export default buildConfig({ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ - db: mongooseAdapter({ url: process.env.DATABASE_URI || '' }), + db: mongooseAdapter({ url: process.env.DATABASE_URL || '' }), collections: [] })`, ) diff --git a/packages/create-payload-app/src/lib/ast/payload-config.ts b/packages/create-payload-app/src/lib/ast/payload-config.ts index 6ad1cd70826..0023ac05cac 100644 --- a/packages/create-payload-app/src/lib/ast/payload-config.ts +++ b/packages/create-payload-app/src/lib/ast/payload-config.ts @@ -182,7 +182,7 @@ export function detectPayloadConfigStructure(sourceFile: SourceFile): DetectionR export function addDatabaseAdapter({ adapter, - envVarName = 'DATABASE_URI', + envVarName = 'DATABASE_URL', sourceFile, }: { adapter: DatabaseAdapter diff --git a/packages/create-payload-app/src/lib/configure-payload-config.ts b/packages/create-payload-app/src/lib/configure-payload-config.ts index 8245ed5a35f..0ccb2e52e0f 100644 --- a/packages/create-payload-app/src/lib/configure-payload-config.ts +++ b/packages/create-payload-app/src/lib/configure-payload-config.ts @@ -17,7 +17,7 @@ function getEnvVarName(dbType: DbType, customEnvName?: string): string { if (dbType === 'vercel-postgres') { return 'POSTGRES_URL' } - return 'DATABASE_URI' + return 'DATABASE_URL' } /** Update payload config with necessary imports and adapters */ diff --git a/packages/create-payload-app/src/lib/manage-env-files.spec.ts b/packages/create-payload-app/src/lib/manage-env-files.spec.ts index 427ca11adfd..0257bea01e1 100644 --- a/packages/create-payload-app/src/lib/manage-env-files.spec.ts +++ b/packages/create-payload-app/src/lib/manage-env-files.spec.ts @@ -60,7 +60,7 @@ describe('createProject', () => { const updatedEnvContent = fse.readFileSync(envFilePath, 'utf-8') expect(updatedEnvContent).toBe( - `# Added by Payload\nPAYLOAD_SECRET=YOUR_SECRET_HERE\nDATABASE_URI=your-connection-string-here`, + `# Added by Payload\nPAYLOAD_SECRET=YOUR_SECRET_HERE\nDATABASE_URL=your-connection-string-here`, ) }) @@ -69,7 +69,7 @@ describe('createProject', () => { fse.ensureFileSync(envExampleFilePath) fse.writeFileSync( envExampleFilePath, - `DATABASE_URI=example-connection-string\nCUSTOM_VAR=custom-value\n`, + `DATABASE_URL=example-connection-string\nCUSTOM_VAR=custom-value\n`, ) await manageEnvFiles({ @@ -87,7 +87,7 @@ describe('createProject', () => { const updatedEnvContent = fse.readFileSync(envFilePath, 'utf-8') expect(updatedEnvContent).toBe( - `DATABASE_URI=example-connection-string\nCUSTOM_VAR=custom-value\nPAYLOAD_SECRET=YOUR_SECRET_HERE\n# Added by Payload`, + `DATABASE_URL=example-connection-string\nCUSTOM_VAR=custom-value\nPAYLOAD_SECRET=YOUR_SECRET_HERE\n# Added by Payload`, ) }) @@ -96,14 +96,14 @@ describe('createProject', () => { fse.ensureFileSync(envFilePath) fse.writeFileSync( envFilePath, - `CUSTOM_VAR=custom-value\nDATABASE_URI=example-connection-string\n`, + `CUSTOM_VAR=custom-value\nDATABASE_URL=example-connection-string\n`, ) // create an .env.example file to ensure that its contents DO NOT override existing .env vars fse.ensureFileSync(envExampleFilePath) fse.writeFileSync( envExampleFilePath, - `CUSTOM_VAR=custom-value-2\nDATABASE_URI=example-connection-string-2\n`, + `CUSTOM_VAR=custom-value-2\nDATABASE_URL=example-connection-string-2\n`, ) await manageEnvFiles({ @@ -121,7 +121,7 @@ describe('createProject', () => { const updatedEnvContent = fse.readFileSync(envFilePath, 'utf-8') expect(updatedEnvContent).toBe( - `# Added by Payload\nPAYLOAD_SECRET=YOUR_SECRET_HERE\nDATABASE_URI=example-connection-string\nCUSTOM_VAR=custom-value`, + `# Added by Payload\nPAYLOAD_SECRET=YOUR_SECRET_HERE\nDATABASE_URL=example-connection-string\nCUSTOM_VAR=custom-value`, ) }) @@ -130,8 +130,8 @@ describe('createProject', () => { cliArgs: { '--debug': true, } as CliArgs, - databaseType: 'mongodb', // this mimics the CLI selection and will be used as the DATABASE_URI - databaseUri: 'mongodb://localhost:27017/test', // this mimics the CLI selection and will be used as the DATABASE_URI + databaseType: 'mongodb', // this mimics the CLI selection and will be used as the DATABASE_URL + databaseUri: 'mongodb://localhost:27017/test', // this mimics the CLI selection and will be used as the DATABASE_URL payloadSecret: 'test-secret', // this mimics the CLI selection and will be used as the PAYLOAD_SECRET projectDir, template: undefined, @@ -140,7 +140,7 @@ describe('createProject', () => { const updatedEnvContent = fse.readFileSync(envFilePath, 'utf-8') expect(updatedEnvContent).toBe( - `# Added by Payload\nPAYLOAD_SECRET=test-secret\nDATABASE_URI=mongodb://localhost:27017/test`, + `# Added by Payload\nPAYLOAD_SECRET=test-secret\nDATABASE_URL=mongodb://localhost:27017/test`, ) // delete the generated .env file and do it again, but this time, omit the databaseUri to ensure the default is generated @@ -150,7 +150,7 @@ describe('createProject', () => { cliArgs: { '--debug': true, } as CliArgs, - databaseType: 'mongodb', // this mimics the CLI selection and will be used as the DATABASE_URI + databaseType: 'mongodb', // this mimics the CLI selection and will be used as the DATABASE_URL databaseUri: '', // omit this to ensure the default is generated based on the selected database type payloadSecret: 'test-secret', projectDir, @@ -159,7 +159,7 @@ describe('createProject', () => { const updatedEnvContentWithDefault = fse.readFileSync(envFilePath, 'utf-8') expect(updatedEnvContentWithDefault).toBe( - `# Added by Payload\nPAYLOAD_SECRET=test-secret\nDATABASE_URI=mongodb://127.0.0.1/your-database-name`, + `# Added by Payload\nPAYLOAD_SECRET=test-secret\nDATABASE_URL=mongodb://127.0.0.1/your-database-name`, ) }) }) diff --git a/packages/create-payload-app/src/lib/manage-env-files.ts b/packages/create-payload-app/src/lib/manage-env-files.ts index 7491eb47ba5..6a726da21d2 100644 --- a/packages/create-payload-app/src/lib/manage-env-files.ts +++ b/packages/create-payload-app/src/lib/manage-env-files.ts @@ -23,12 +23,12 @@ const sanitizeEnv = ({ let withDefaults = contents if ( - !contents.includes('DATABASE_URI') && + !contents.includes('DATABASE_URL') && !contents.includes('POSTGRES_URL') && - !contents.includes('MONGODB_URI') && + !contents.includes('MONGODB_URL') && databaseType !== 'd1-sqlite' ) { - withDefaults += '\nDATABASE_URI=your-connection-string-here' + withDefaults += '\nDATABASE_URL=your-connection-string-here' } if (!contents.includes('PAYLOAD_SECRET')) { @@ -48,7 +48,7 @@ const sanitizeEnv = ({ return } - if (key === 'DATABASE_URI' || key === 'POSTGRES_URL' || key === 'MONGODB_URI') { + if (key === 'DATABASE_URL' || key === 'POSTGRES_URL' || key === 'MONGODB_URL') { const dbChoice = databaseType ? dbChoiceRecord[databaseType] : null if (dbChoice) { @@ -58,7 +58,7 @@ const sanitizeEnv = ({ line = databaseType === 'vercel-postgres' ? `POSTGRES_URL=${placeholderUri}` - : `DATABASE_URI=${placeholderUri}` + : `DATABASE_URL=${placeholderUri}` } else { line = `${key}=${value}` } diff --git a/packages/db-mongodb/README.md b/packages/db-mongodb/README.md index cd52f67aa84..e9dc16c01c8 100644 --- a/packages/db-mongodb/README.md +++ b/packages/db-mongodb/README.md @@ -19,7 +19,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), // ...rest of config }) diff --git a/packages/db-postgres/README.md b/packages/db-postgres/README.md index e7542964b56..c5be6bf274c 100644 --- a/packages/db-postgres/README.md +++ b/packages/db-postgres/README.md @@ -20,7 +20,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, }), // ...rest of config diff --git a/packages/db-sqlite/README.md b/packages/db-sqlite/README.md index 9191b62e829..76e6da7bd32 100644 --- a/packages/db-sqlite/README.md +++ b/packages/db-sqlite/README.md @@ -20,7 +20,7 @@ import { sqliteAdapter } from '@payloadcms/db-sqlite' export default buildConfig({ db: sqliteAdapter({ client: { - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }, }), // ...rest of config diff --git a/packages/db-vercel-postgres/README.md b/packages/db-vercel-postgres/README.md index ed25dac58ff..f56167cbec8 100644 --- a/packages/db-vercel-postgres/README.md +++ b/packages/db-vercel-postgres/README.md @@ -22,7 +22,7 @@ import { vercelPostgresAdapter } from '@payloadcms/db-vercel-postgres' export default buildConfig({ db: vercelPostgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, }), // ...rest of config diff --git a/packages/plugin-mcp/src/mcp/helpers/config.ts b/packages/plugin-mcp/src/mcp/helpers/config.ts index c306af9844c..fef8795c542 100644 --- a/packages/plugin-mcp/src/mcp/helpers/config.ts +++ b/packages/plugin-mcp/src/mcp/helpers/config.ts @@ -161,7 +161,7 @@ export function updateDatabaseConfig(content: string, databaseConfig: DatabaseCo ) } - const dbConfig = `db: mongooseAdapter({\n url: process.env.DATABASE_URI || '${databaseConfig.url || ''}',\n })` + const dbConfig = `db: mongooseAdapter({\n url: process.env.DATABASE_URL || '${databaseConfig.url || ''}',\n })` content = content.replace(dbRegex, `${dbConfig},`) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 35e1108593a..e732b84516c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,6 @@ overrides: cross-env: 7.0.3 dotenv: 16.4.7 graphql: ^16.8.1 - mongodb-memory-server: 10.1.4 react: 19.2.1 react-dom: 19.2.1 typescript: 5.7.3 @@ -138,9 +137,6 @@ importers: minimist: specifier: 1.2.8 version: 1.2.8 - mongodb-memory-server: - specifier: 10.1.4 - version: 10.1.4(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) mongoose: specifier: 8.15.1 version: 8.15.1(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) @@ -1875,7 +1871,7 @@ importers: version: 16.9.0 next: specifier: 15.4.10 - version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: workspace:* version: link:../../packages/payload @@ -2017,7 +2013,7 @@ importers: version: 8.6.0(react@19.2.1) geist: specifier: ^1.3.0 - version: 1.4.2(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) graphql: specifier: ^16.8.1 version: 16.9.0 @@ -2029,7 +2025,7 @@ importers: version: 0.477.0(react@19.2.1) next: specifier: 15.4.10 - version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes: specifier: 0.4.6 version: 0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -25098,10 +25094,6 @@ snapshots: - encoding - supports-color - geist@1.4.2(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): - dependencies: - next: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) - geist@1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) diff --git a/templates/_agents/AGENTS.md b/templates/_agents/AGENTS.md index 633b29b1f61..ac853cf3d0e 100644 --- a/templates/_agents/AGENTS.md +++ b/templates/_agents/AGENTS.md @@ -59,7 +59,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/_agents/rules/adapters.md b/templates/_agents/rules/adapters.md index 49b8b3367fc..b14425166d9 100644 --- a/templates/_agents/rules/adapters.md +++ b/templates/_agents/rules/adapters.md @@ -15,7 +15,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -28,7 +28,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, push: false, // Don't auto-push schema changes migrationDir: './migrations', diff --git a/templates/_agents/rules/payload-overview.md b/templates/_agents/rules/payload-overview.md index 290c47822ab..c37e0941870 100644 --- a/templates/_agents/rules/payload-overview.md +++ b/templates/_agents/rules/payload-overview.md @@ -57,7 +57,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/_template/.env.example b/templates/_template/.env.example index 566f44738d4..99e5a632671 100644 --- a/templates/_template/.env.example +++ b/templates/_template/.env.example @@ -1,2 +1,2 @@ -DATABASE_URI=mongodb://127.0.0.1/your-database-name +DATABASE_URL=mongodb://127.0.0.1/your-database-name PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/templates/_template/docker-compose.yml b/templates/_template/docker-compose.yml index 3aba7cc7e2a..4ed0d24c9ae 100644 --- a/templates/_template/docker-compose.yml +++ b/templates/_template/docker-compose.yml @@ -1,10 +1,10 @@ -version: '3' +version: "3" services: payload: image: node:18-alpine ports: - - '3000:3000' + - "3000:3000" volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -16,11 +16,11 @@ services: env_file: - .env - # Ensure your DATABASE_URI uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name + # Ensure your DATABASE_URL uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name mongo: image: mongo:latest ports: - - '27017:27017' + - "27017:27017" command: - --storageEngine=wiredTiger volumes: diff --git a/templates/_template/src/payload.config.ts b/templates/_template/src/payload.config.ts index f291382709a..e8474cd36be 100644 --- a/templates/_template/src/payload.config.ts +++ b/templates/_template/src/payload.config.ts @@ -25,7 +25,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), sharp, plugins: [], diff --git a/templates/blank/.cursor/rules/adapters.md b/templates/blank/.cursor/rules/adapters.md index 49b8b3367fc..b14425166d9 100644 --- a/templates/blank/.cursor/rules/adapters.md +++ b/templates/blank/.cursor/rules/adapters.md @@ -15,7 +15,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -28,7 +28,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, push: false, // Don't auto-push schema changes migrationDir: './migrations', diff --git a/templates/blank/.cursor/rules/payload-overview.md b/templates/blank/.cursor/rules/payload-overview.md index 290c47822ab..c37e0941870 100644 --- a/templates/blank/.cursor/rules/payload-overview.md +++ b/templates/blank/.cursor/rules/payload-overview.md @@ -57,7 +57,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/blank/.env.example b/templates/blank/.env.example index 566f44738d4..99e5a632671 100644 --- a/templates/blank/.env.example +++ b/templates/blank/.env.example @@ -1,2 +1,2 @@ -DATABASE_URI=mongodb://127.0.0.1/your-database-name +DATABASE_URL=mongodb://127.0.0.1/your-database-name PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/templates/blank/AGENTS.md b/templates/blank/AGENTS.md index 633b29b1f61..ac853cf3d0e 100644 --- a/templates/blank/AGENTS.md +++ b/templates/blank/AGENTS.md @@ -59,7 +59,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/blank/README.md b/templates/blank/README.md index 4a2dde69c19..7876a70c56d 100644 --- a/templates/blank/README.md +++ b/templates/blank/README.md @@ -17,7 +17,7 @@ After you click the `Deploy` button above, you'll want to have standalone copy o ### Development 1. First [clone the repo](#clone) if you have not done so already -2. `cd my-project && cp .env.example .env` to copy the example environment variables. You'll need to add the `MONGODB_URI` from your Cloud project to your `.env` if you want to use S3 storage and the MongoDB database that was created for you. +2. `cd my-project && cp .env.example .env` to copy the example environment variables. You'll need to add the `MONGODB_URL` from your Cloud project to your `.env` if you want to use S3 storage and the MongoDB database that was created for you. 3. `pnpm install && pnpm dev` to install dependencies and start the dev server 4. open `http://localhost:3000` to open the app in your browser @@ -30,8 +30,8 @@ If you prefer to use Docker for local development instead of a local MongoDB ins To do so, follow these steps: -- Modify the `MONGODB_URI` in your `.env` file to `mongodb://127.0.0.1/` -- Modify the `docker-compose.yml` file's `MONGODB_URI` to match the above `` +- Modify the `MONGODB_URL` in your `.env` file to `mongodb://127.0.0.1/` +- Modify the `docker-compose.yml` file's `MONGODB_URL` to match the above `` - Run `docker-compose up` to start the database, optionally pass `-d` to run in the background. ## How it works diff --git a/templates/blank/docker-compose.yml b/templates/blank/docker-compose.yml index 3aba7cc7e2a..4ed0d24c9ae 100644 --- a/templates/blank/docker-compose.yml +++ b/templates/blank/docker-compose.yml @@ -1,10 +1,10 @@ -version: '3' +version: "3" services: payload: image: node:18-alpine ports: - - '3000:3000' + - "3000:3000" volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -16,11 +16,11 @@ services: env_file: - .env - # Ensure your DATABASE_URI uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name + # Ensure your DATABASE_URL uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name mongo: image: mongo:latest ports: - - '27017:27017' + - "27017:27017" command: - --storageEngine=wiredTiger volumes: diff --git a/templates/blank/src/payload.config.ts b/templates/blank/src/payload.config.ts index f291382709a..e8474cd36be 100644 --- a/templates/blank/src/payload.config.ts +++ b/templates/blank/src/payload.config.ts @@ -25,7 +25,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), sharp, plugins: [], diff --git a/templates/ecommerce/.cursor/rules/adapters.md b/templates/ecommerce/.cursor/rules/adapters.md index 49b8b3367fc..b14425166d9 100644 --- a/templates/ecommerce/.cursor/rules/adapters.md +++ b/templates/ecommerce/.cursor/rules/adapters.md @@ -15,7 +15,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -28,7 +28,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, push: false, // Don't auto-push schema changes migrationDir: './migrations', diff --git a/templates/ecommerce/.cursor/rules/payload-overview.md b/templates/ecommerce/.cursor/rules/payload-overview.md index 290c47822ab..c37e0941870 100644 --- a/templates/ecommerce/.cursor/rules/payload-overview.md +++ b/templates/ecommerce/.cursor/rules/payload-overview.md @@ -57,7 +57,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/ecommerce/.env.example b/templates/ecommerce/.env.example index 71879e98759..60b183197cb 100644 --- a/templates/ecommerce/.env.example +++ b/templates/ecommerce/.env.example @@ -1,5 +1,5 @@ PAYLOAD_SECRET=mygeneratedsecret -DATABASE_URI=mongodb://127.0.0.1/template-ecommerce +DATABASE_URL=mongodb://127.0.0.1/template-ecommerce COMPANY_NAME="Payload Inc." TWITTER_CREATOR="@payloadcms" diff --git a/templates/ecommerce/AGENTS.md b/templates/ecommerce/AGENTS.md index 633b29b1f61..ac853cf3d0e 100644 --- a/templates/ecommerce/AGENTS.md +++ b/templates/ecommerce/AGENTS.md @@ -59,7 +59,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/ecommerce/src/payload.config.ts b/templates/ecommerce/src/payload.config.ts index 3f33f35a2fd..fe70967cc87 100644 --- a/templates/ecommerce/src/payload.config.ts +++ b/templates/ecommerce/src/payload.config.ts @@ -40,7 +40,7 @@ export default buildConfig({ }, collections: [Users, Pages, Categories, Media], db: mongooseAdapter({ - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), editor: lexicalEditor({ features: () => { diff --git a/templates/plugin/README.md b/templates/plugin/README.md index 334653888d9..9c813814d92 100644 --- a/templates/plugin/README.md +++ b/templates/plugin/README.md @@ -71,7 +71,7 @@ In the root folder, you will see various files that relate to the configuration In the dev folder, you’ll find a basic payload project, created with `npx create-payload-app` and the blank template. -**IMPORTANT**: Make a copy of the `.env.example` file and rename it to `.env`. Update the `DATABASE_URI` to match the database you are using and your plugin name. Update `PAYLOAD_SECRET` to a unique string. +**IMPORTANT**: Make a copy of the `.env.example` file and rename it to `.env`. Update the `DATABASE_URL` to match the database you are using and your plugin name. Update `PAYLOAD_SECRET` to a unique string. **You will not be able to run `pnpm/yarn dev` until you have created this `.env` file.** `myPlugin` has already been added to the `payload.config()` file in this project. diff --git a/templates/plugin/dev/.env.example b/templates/plugin/dev/.env.example index 36c6f26c591..e6095501e15 100644 --- a/templates/plugin/dev/.env.example +++ b/templates/plugin/dev/.env.example @@ -1,2 +1,2 @@ -DATABASE_URI=mongodb://127.0.0.1/payload-plugin-template +DATABASE_URL=mongodb://127.0.0.1/payload-plugin-template PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/templates/plugin/dev/payload.config.ts b/templates/plugin/dev/payload.config.ts index 60e59c9432f..854022d9580 100644 --- a/templates/plugin/dev/payload.config.ts +++ b/templates/plugin/dev/payload.config.ts @@ -26,7 +26,7 @@ const buildConfigWithMemoryDB = async () => { }, }) - process.env.DATABASE_URI = `${memoryDB.getUri()}&retryWrites=true` + process.env.DATABASE_URL = `${memoryDB.getUri()}&retryWrites=true` } return buildConfig({ @@ -50,7 +50,7 @@ const buildConfigWithMemoryDB = async () => { ], db: mongooseAdapter({ ensureIndexes: true, - url: process.env.DATABASE_URI || '', + url: process.env.DATABASE_URL || '', }), editor: lexicalEditor(), email: testEmailAdapter, diff --git a/templates/website/.cursor/rules/adapters.md b/templates/website/.cursor/rules/adapters.md index 49b8b3367fc..b14425166d9 100644 --- a/templates/website/.cursor/rules/adapters.md +++ b/templates/website/.cursor/rules/adapters.md @@ -15,7 +15,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -28,7 +28,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, push: false, // Don't auto-push schema changes migrationDir: './migrations', diff --git a/templates/website/.cursor/rules/payload-overview.md b/templates/website/.cursor/rules/payload-overview.md index 290c47822ab..c37e0941870 100644 --- a/templates/website/.cursor/rules/payload-overview.md +++ b/templates/website/.cursor/rules/payload-overview.md @@ -57,7 +57,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/website/.env.example b/templates/website/.env.example index 8eac48f1b9e..57bee947861 100644 --- a/templates/website/.env.example +++ b/templates/website/.env.example @@ -1,8 +1,8 @@ # Database connection string -DATABASE_URI=mongodb://127.0.0.1/your-database-name +DATABASE_URL=mongodb://127.0.0.1/your-database-name # Or use a PG connection string -#DATABASE_URI=postgresql://127.0.0.1:5432/your-database-name +#DATABASE_URL=postgresql://127.0.0.1:5432/your-database-name # Used to encrypt JWT tokens PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/templates/website/AGENTS.md b/templates/website/AGENTS.md index 633b29b1f61..ac853cf3d0e 100644 --- a/templates/website/AGENTS.md +++ b/templates/website/AGENTS.md @@ -59,7 +59,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/website/src/environment.d.ts b/templates/website/src/environment.d.ts index 846d2344e2e..06efb5d577f 100644 --- a/templates/website/src/environment.d.ts +++ b/templates/website/src/environment.d.ts @@ -2,7 +2,7 @@ declare global { namespace NodeJS { interface ProcessEnv { PAYLOAD_SECRET: string - DATABASE_URI: string + DATABASE_URL: string NEXT_PUBLIC_SERVER_URL: string VERCEL_PROJECT_PRODUCTION_URL: string } diff --git a/templates/website/src/payload.config.ts b/templates/website/src/payload.config.ts index 357632ddaf2..d409d8c31a1 100644 --- a/templates/website/src/payload.config.ts +++ b/templates/website/src/payload.config.ts @@ -58,7 +58,7 @@ export default buildConfig({ // This config helps us configure global or default features that the other editors can inherit editor: defaultLexical, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), collections: [Pages, Posts, Media, Categories, Users], cors: [getServerSideURL()].filter(Boolean), diff --git a/templates/with-cloudflare-d1/.cursor/rules/adapters.md b/templates/with-cloudflare-d1/.cursor/rules/adapters.md index 49b8b3367fc..b14425166d9 100644 --- a/templates/with-cloudflare-d1/.cursor/rules/adapters.md +++ b/templates/with-cloudflare-d1/.cursor/rules/adapters.md @@ -15,7 +15,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -28,7 +28,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, push: false, // Don't auto-push schema changes migrationDir: './migrations', diff --git a/templates/with-cloudflare-d1/.cursor/rules/payload-overview.md b/templates/with-cloudflare-d1/.cursor/rules/payload-overview.md index 290c47822ab..c37e0941870 100644 --- a/templates/with-cloudflare-d1/.cursor/rules/payload-overview.md +++ b/templates/with-cloudflare-d1/.cursor/rules/payload-overview.md @@ -57,7 +57,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/with-cloudflare-d1/AGENTS.md b/templates/with-cloudflare-d1/AGENTS.md index 633b29b1f61..ac853cf3d0e 100644 --- a/templates/with-cloudflare-d1/AGENTS.md +++ b/templates/with-cloudflare-d1/AGENTS.md @@ -59,7 +59,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/with-postgres/.cursor/rules/adapters.md b/templates/with-postgres/.cursor/rules/adapters.md index 49b8b3367fc..b14425166d9 100644 --- a/templates/with-postgres/.cursor/rules/adapters.md +++ b/templates/with-postgres/.cursor/rules/adapters.md @@ -15,7 +15,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -28,7 +28,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, push: false, // Don't auto-push schema changes migrationDir: './migrations', diff --git a/templates/with-postgres/.cursor/rules/payload-overview.md b/templates/with-postgres/.cursor/rules/payload-overview.md index 290c47822ab..c37e0941870 100644 --- a/templates/with-postgres/.cursor/rules/payload-overview.md +++ b/templates/with-postgres/.cursor/rules/payload-overview.md @@ -57,7 +57,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/with-postgres/.env.example b/templates/with-postgres/.env.example index 31dbf0f034a..c14561da4e6 100644 --- a/templates/with-postgres/.env.example +++ b/templates/with-postgres/.env.example @@ -1,2 +1,2 @@ -DATABASE_URI=postgresql://127.0.0.1:5432/your-database-name -PAYLOAD_SECRET=YOUR_SECRET_HERE \ No newline at end of file +DATABASE_URL=postgresql://127.0.0.1:5432/your-database-name +PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/templates/with-postgres/AGENTS.md b/templates/with-postgres/AGENTS.md index 633b29b1f61..ac853cf3d0e 100644 --- a/templates/with-postgres/AGENTS.md +++ b/templates/with-postgres/AGENTS.md @@ -59,7 +59,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/with-postgres/docker-compose.yml b/templates/with-postgres/docker-compose.yml index 40e4acb761e..0d684d896c7 100644 --- a/templates/with-postgres/docker-compose.yml +++ b/templates/with-postgres/docker-compose.yml @@ -1,10 +1,10 @@ -version: '3' +version: "3" services: payload: image: node:20-alpine ports: - - '3000:3000' + - "3000:3000" volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -16,14 +16,14 @@ services: env_file: - .env - # Ensure your DATABASE_URI uses 'postgresql' as the hostname ie. postgresql://127.0.0.1:5432/your-database-name + # Ensure your DATABASE_URL uses 'postgresql' as the hostname ie. postgresql://127.0.0.1:5432/your-database-name postgres: restart: always image: postgres:latest volumes: - pgdata:/var/lib/postgresql/data ports: - - '5432:5432' + - "5432:5432" environment: POSTGRES_USER: postgres POSTGRES_DB: your-database-name # THIS MUST MATCH YOUR DB NAME IN .env diff --git a/templates/with-postgres/src/payload.config.ts b/templates/with-postgres/src/payload.config.ts index 961f9c40c99..debb2fd92e7 100644 --- a/templates/with-postgres/src/payload.config.ts +++ b/templates/with-postgres/src/payload.config.ts @@ -26,7 +26,7 @@ export default buildConfig({ }, db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI || '', + connectionString: process.env.DATABASE_URL || '', }, }), sharp, diff --git a/templates/with-vercel-mongodb/.cursor/rules/adapters.md b/templates/with-vercel-mongodb/.cursor/rules/adapters.md index 49b8b3367fc..b14425166d9 100644 --- a/templates/with-vercel-mongodb/.cursor/rules/adapters.md +++ b/templates/with-vercel-mongodb/.cursor/rules/adapters.md @@ -15,7 +15,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -28,7 +28,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, push: false, // Don't auto-push schema changes migrationDir: './migrations', diff --git a/templates/with-vercel-mongodb/.cursor/rules/payload-overview.md b/templates/with-vercel-mongodb/.cursor/rules/payload-overview.md index 290c47822ab..c37e0941870 100644 --- a/templates/with-vercel-mongodb/.cursor/rules/payload-overview.md +++ b/templates/with-vercel-mongodb/.cursor/rules/payload-overview.md @@ -57,7 +57,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/with-vercel-mongodb/.env.example b/templates/with-vercel-mongodb/.env.example index d77180b8142..42067211337 100644 --- a/templates/with-vercel-mongodb/.env.example +++ b/templates/with-vercel-mongodb/.env.example @@ -1,2 +1,2 @@ -MONGODB_URI=mongodb://127.0.0.1/your-database-name -PAYLOAD_SECRET=YOUR_SECRET_HERE \ No newline at end of file +MONGODB_URL=mongodb://127.0.0.1/your-database-name +PAYLOAD_SECRET=YOUR_SECRET_HERE diff --git a/templates/with-vercel-mongodb/AGENTS.md b/templates/with-vercel-mongodb/AGENTS.md index 633b29b1f61..ac853cf3d0e 100644 --- a/templates/with-vercel-mongodb/AGENTS.md +++ b/templates/with-vercel-mongodb/AGENTS.md @@ -59,7 +59,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/with-vercel-mongodb/README.md b/templates/with-vercel-mongodb/README.md index 9cd01a88d94..418c617ba1d 100644 --- a/templates/with-vercel-mongodb/README.md +++ b/templates/with-vercel-mongodb/README.md @@ -38,7 +38,7 @@ After you click the `Deploy` button above, you'll want to have standalone copy o ### Development 1. First [clone the repo](#clone) if you have not done so already -2. `cd my-project && cp .env.example .env` to copy the example environment variables. You'll need to add the `MONGODB_URI` and `BLOB_READ_WRITE_TOKEN` from your Vercel project to your `.env` if you want to use Vercel Blob and the Neon database that was created for you. +2. `cd my-project && cp .env.example .env` to copy the example environment variables. You'll need to add the `MONGODB_URL` and `BLOB_READ_WRITE_TOKEN` from your Vercel project to your `.env` if you want to use Vercel Blob and the Neon database that was created for you. 3. `pnpm install && pnpm dev` to install dependencies and start the dev server 4. open `http://localhost:3000` to open the app in your browser @@ -51,8 +51,8 @@ If you prefer to use Docker for local development instead of a local MongoDB ins To do so, follow these steps: -- Modify the `MONGODB_URI` in your `.env` file to `mongodb://127.0.0.1/` -- Modify the `docker-compose.yml` file's `MONGODB_URI` to match the above `` +- Modify the `MONGODB_URL` in your `.env` file to `mongodb://127.0.0.1/` +- Modify the `docker-compose.yml` file's `MONGODB_URL` to match the above `` - Run `docker-compose up` to start the database, optionally pass `-d` to run in the background. ## How it works diff --git a/templates/with-vercel-mongodb/docker-compose.yml b/templates/with-vercel-mongodb/docker-compose.yml index 3aba7cc7e2a..4ed0d24c9ae 100644 --- a/templates/with-vercel-mongodb/docker-compose.yml +++ b/templates/with-vercel-mongodb/docker-compose.yml @@ -1,10 +1,10 @@ -version: '3' +version: "3" services: payload: image: node:18-alpine ports: - - '3000:3000' + - "3000:3000" volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -16,11 +16,11 @@ services: env_file: - .env - # Ensure your DATABASE_URI uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name + # Ensure your DATABASE_URL uses 'mongo' as the hostname ie. mongodb://mongo/my-db-name mongo: image: mongo:latest ports: - - '27017:27017' + - "27017:27017" command: - --storageEngine=wiredTiger volumes: diff --git a/templates/with-vercel-mongodb/src/payload.config.ts b/templates/with-vercel-mongodb/src/payload.config.ts index 8aefe6a38f2..b4a74d23b05 100644 --- a/templates/with-vercel-mongodb/src/payload.config.ts +++ b/templates/with-vercel-mongodb/src/payload.config.ts @@ -24,7 +24,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.MONGODB_URI || '', + url: process.env.MONGODB_URL || '', }), plugins: [ vercelBlobStorage({ diff --git a/templates/with-vercel-postgres/.cursor/rules/adapters.md b/templates/with-vercel-postgres/.cursor/rules/adapters.md index 49b8b3367fc..b14425166d9 100644 --- a/templates/with-vercel-postgres/.cursor/rules/adapters.md +++ b/templates/with-vercel-postgres/.cursor/rules/adapters.md @@ -15,7 +15,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -28,7 +28,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, push: false, // Don't auto-push schema changes migrationDir: './migrations', diff --git a/templates/with-vercel-postgres/.cursor/rules/payload-overview.md b/templates/with-vercel-postgres/.cursor/rules/payload-overview.md index 290c47822ab..c37e0941870 100644 --- a/templates/with-vercel-postgres/.cursor/rules/payload-overview.md +++ b/templates/with-vercel-postgres/.cursor/rules/payload-overview.md @@ -57,7 +57,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/with-vercel-postgres/AGENTS.md b/templates/with-vercel-postgres/AGENTS.md index 633b29b1f61..ac853cf3d0e 100644 --- a/templates/with-vercel-postgres/AGENTS.md +++ b/templates/with-vercel-postgres/AGENTS.md @@ -59,7 +59,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/with-vercel-postgres/docker-compose.yml b/templates/with-vercel-postgres/docker-compose.yml index 40e4acb761e..0d684d896c7 100644 --- a/templates/with-vercel-postgres/docker-compose.yml +++ b/templates/with-vercel-postgres/docker-compose.yml @@ -1,10 +1,10 @@ -version: '3' +version: "3" services: payload: image: node:20-alpine ports: - - '3000:3000' + - "3000:3000" volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -16,14 +16,14 @@ services: env_file: - .env - # Ensure your DATABASE_URI uses 'postgresql' as the hostname ie. postgresql://127.0.0.1:5432/your-database-name + # Ensure your DATABASE_URL uses 'postgresql' as the hostname ie. postgresql://127.0.0.1:5432/your-database-name postgres: restart: always image: postgres:latest volumes: - pgdata:/var/lib/postgresql/data ports: - - '5432:5432' + - "5432:5432" environment: POSTGRES_USER: postgres POSTGRES_DB: your-database-name # THIS MUST MATCH YOUR DB NAME IN .env diff --git a/templates/with-vercel-website/.cursor/rules/adapters.md b/templates/with-vercel-website/.cursor/rules/adapters.md index 49b8b3367fc..b14425166d9 100644 --- a/templates/with-vercel-website/.cursor/rules/adapters.md +++ b/templates/with-vercel-website/.cursor/rules/adapters.md @@ -15,7 +15,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -28,7 +28,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, push: false, // Don't auto-push schema changes migrationDir: './migrations', diff --git a/templates/with-vercel-website/.cursor/rules/payload-overview.md b/templates/with-vercel-website/.cursor/rules/payload-overview.md index 290c47822ab..c37e0941870 100644 --- a/templates/with-vercel-website/.cursor/rules/payload-overview.md +++ b/templates/with-vercel-website/.cursor/rules/payload-overview.md @@ -57,7 +57,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/with-vercel-website/AGENTS.md b/templates/with-vercel-website/AGENTS.md index 633b29b1f61..ac853cf3d0e 100644 --- a/templates/with-vercel-website/AGENTS.md +++ b/templates/with-vercel-website/AGENTS.md @@ -59,7 +59,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/templates/with-vercel-website/src/environment.d.ts b/templates/with-vercel-website/src/environment.d.ts index 846d2344e2e..06efb5d577f 100644 --- a/templates/with-vercel-website/src/environment.d.ts +++ b/templates/with-vercel-website/src/environment.d.ts @@ -2,7 +2,7 @@ declare global { namespace NodeJS { interface ProcessEnv { PAYLOAD_SECRET: string - DATABASE_URI: string + DATABASE_URL: string NEXT_PUBLIC_SERVER_URL: string VERCEL_PROJECT_PRODUCTION_URL: string } diff --git a/test/create-payload-app/fixtures/payload-configs/minimal.ts b/test/create-payload-app/fixtures/payload-configs/minimal.ts index 3c6bc4e8927..59a7007d8b8 100644 --- a/test/create-payload-app/fixtures/payload-configs/minimal.ts +++ b/test/create-payload-app/fixtures/payload-configs/minimal.ts @@ -4,7 +4,7 @@ import { buildConfig } from 'payload' export default buildConfig({ collections: [], - db: mongooseAdapter({ url: process.env.DATABASE_URI || '' }), + db: mongooseAdapter({ url: process.env.DATABASE_URL || '' }), editor: lexicalEditor(), secret: process.env.PAYLOAD_SECRET || '', }) diff --git a/test/create-payload-app/fixtures/payload-configs/multiple-buildconfig.ts b/test/create-payload-app/fixtures/payload-configs/multiple-buildconfig.ts index cd2f38501a2..6de9aa1de06 100644 --- a/test/create-payload-app/fixtures/payload-configs/multiple-buildconfig.ts +++ b/test/create-payload-app/fixtures/payload-configs/multiple-buildconfig.ts @@ -8,5 +8,5 @@ const helperConfig = buildConfig({ export default buildConfig({ collections: [], - db: mongooseAdapter({ url: process.env.DATABASE_URI || '' }), + db: mongooseAdapter({ url: process.env.DATABASE_URL || '' }), }) diff --git a/test/create-payload-app/fixtures/payload-configs/postgres-adapter.ts b/test/create-payload-app/fixtures/payload-configs/postgres-adapter.ts index 002556db768..aa563f6abe8 100644 --- a/test/create-payload-app/fixtures/payload-configs/postgres-adapter.ts +++ b/test/create-payload-app/fixtures/payload-configs/postgres-adapter.ts @@ -6,7 +6,7 @@ export default buildConfig({ collections: [], db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, }), editor: lexicalEditor(), diff --git a/test/create-payload-app/fixtures/payload-configs/with-alias.ts b/test/create-payload-app/fixtures/payload-configs/with-alias.ts index 527ab33d3b0..ad8939f5bbc 100644 --- a/test/create-payload-app/fixtures/payload-configs/with-alias.ts +++ b/test/create-payload-app/fixtures/payload-configs/with-alias.ts @@ -3,5 +3,5 @@ import { buildConfig as createConfig } from 'payload' export default createConfig({ collections: [], - db: mongooseAdapter({ url: process.env.DATABASE_URI || '' }), + db: mongooseAdapter({ url: process.env.DATABASE_URL || '' }), }) diff --git a/test/create-payload-app/fixtures/payload-configs/with-other-imports.ts b/test/create-payload-app/fixtures/payload-configs/with-other-imports.ts index 457d39f140a..a2c12c5c45b 100644 --- a/test/create-payload-app/fixtures/payload-configs/with-other-imports.ts +++ b/test/create-payload-app/fixtures/payload-configs/with-other-imports.ts @@ -11,6 +11,6 @@ const Users: CollectionConfig = { export default buildConfig({ collections: [Users], - db: mongooseAdapter({ url: process.env.DATABASE_URI || '' }), + db: mongooseAdapter({ url: process.env.DATABASE_URL || '' }), editor: lexicalEditor(), }) diff --git a/test/create-payload-app/fixtures/payload-configs/with-storage.ts b/test/create-payload-app/fixtures/payload-configs/with-storage.ts index 946eaf26a2c..8ae8e88ed53 100644 --- a/test/create-payload-app/fixtures/payload-configs/with-storage.ts +++ b/test/create-payload-app/fixtures/payload-configs/with-storage.ts @@ -4,7 +4,7 @@ import { buildConfig } from 'payload' export default buildConfig({ collections: [], - db: mongooseAdapter({ url: process.env.DATABASE_URI || '' }), + db: mongooseAdapter({ url: process.env.DATABASE_URL || '' }), plugins: [ s3Storage({ bucket: process.env.S3_BUCKET || '', diff --git a/test/dev.ts b/test/dev.ts index 2b29b847db6..c7c94a779a9 100644 --- a/test/dev.ts +++ b/test/dev.ts @@ -11,7 +11,6 @@ import { loadEnv } from 'payload/node' import { parse } from 'url' import { getNextRootDir } from './helpers/getNextRootDir.js' -import startMemoryDB from './helpers/startMemoryDB.js' import { runInit } from './runInit.js' import { child } from './safelyRunScript.js' import { createTestHooks } from './testHooks.js' @@ -25,13 +24,6 @@ if (prod) { process.env.PAYLOAD_TEST_PROD = 'true' } -const shouldStartMemoryDB = - process.argv.includes('--start-memory-db') || process.env.START_MEMORY_DB === 'true' -if (shouldStartMemoryDB) { - process.argv = process.argv.filter((arg) => arg !== '--start-memory-db') - process.env.START_MEMORY_DB = 'true' -} - loadEnv() const filename = fileURLToPath(import.meta.url) @@ -71,12 +63,8 @@ const { rootDir, adminRoute } = getNextRootDir(testSuiteArg) await runInit(testSuiteArg, true) -if (shouldStartMemoryDB) { - await startMemoryDB() -} - // This is needed to forward the environment variables to the next process that were created after loadEnv() -// for example process.env.MONGODB_MEMORY_SERVER_URI otherwise app.prepare() will clear them +// for example process.env.DATABASE_URL otherwise app.prepare() will clear them nextEnvImport.updateInitialEnv(process.env) // Open the admin if the -o flag is passed diff --git a/test/generateDatabaseAdapter.ts b/test/generateDatabaseAdapter.ts index e869204fa78..985251b9090 100644 --- a/test/generateDatabaseAdapter.ts +++ b/test/generateDatabaseAdapter.ts @@ -7,12 +7,9 @@ const dirname = path.dirname(filename) const mongooseAdapterArgs = ` ensureIndexes: true, - // required for connect to detect that we are using a memory server - mongoMemoryServer: global._mongoMemoryServer, url: - process.env.MONGODB_MEMORY_SERVER_URI || - process.env.DATABASE_URI || - 'mongodb://127.0.0.1/payloadtests', + process.env.MONGODB_URL || process.env.DATABASE_URL || + 'mongodb://payload:payload@localhost:27017/payload?authSource=admin&directConnection=true&replicaSet=rs0', ` export const allDatabaseAdapters = { @@ -22,6 +19,18 @@ export const allDatabaseAdapters = { export const databaseAdapter = mongooseAdapter({ ${mongooseAdapterArgs} })`, + // mongodb-atlas uses Docker-based MongoDB Atlas Local (all-in-one with search) + // Start with: pnpm docker:mongodb-atlas:start + // Runs on port 27018 to avoid conflicts with mongodb + 'mongodb-atlas': ` + import { mongooseAdapter } from '@payloadcms/db-mongodb' + + export const databaseAdapter = mongooseAdapter({ + ensureIndexes: true, + url: + process.env.MONGODB_ATLAS_URL || process.env.DATABASE_URL || + 'mongodb://localhost:27018/payload?directConnection=true&replicaSet=mongodb-atlas-local', + })`, cosmosdb: ` import { mongooseAdapter, compatibilityOptions } from '@payloadcms/db-mongodb' @@ -53,7 +62,7 @@ export const allDatabaseAdapters = { export const databaseAdapter = postgresAdapter({ pool: { - connectionString: process.env.POSTGRES_URL || 'postgres://127.0.0.1:5432/payloadtests', + connectionString: process.env.POSTGRES_URL || process.env.DATABASE_URL || 'postgres://payload:payload@127.0.0.1:5433/payload', }, })`, 'postgres-custom-schema': ` @@ -61,7 +70,7 @@ export const allDatabaseAdapters = { export const databaseAdapter = postgresAdapter({ pool: { - connectionString: process.env.POSTGRES_URL || 'postgres://127.0.0.1:5432/payloadtests', + connectionString: process.env.POSTGRES_URL || process.env.DATABASE_URL || 'postgres://payload:payload@127.0.0.1:5433/payload', }, schemaName: 'custom', })`, @@ -71,7 +80,7 @@ export const allDatabaseAdapters = { export const databaseAdapter = postgresAdapter({ idType: 'uuid', pool: { - connectionString: process.env.POSTGRES_URL || 'postgres://127.0.0.1:5432/payloadtests', + connectionString: process.env.POSTGRES_URL || process.env.DATABASE_URL || 'postgres://payload:payload@127.0.0.1:5433/payload', }, })`, 'postgres-read-replica': ` @@ -79,7 +88,7 @@ export const allDatabaseAdapters = { export const databaseAdapter = postgresAdapter({ pool: { - connectionString: process.env.POSTGRES_URL, + connectionString: process.env.POSTGRES_URL || process.env.DATABASE_URL, }, readReplicas: [process.env.POSTGRES_REPLICA_URL], }) @@ -89,7 +98,7 @@ export const allDatabaseAdapters = { export const databaseAdapter = vercelPostgresAdapter({ pool: { - connectionString: process.env.POSTGRES_URL, + connectionString: process.env.POSTGRES_URL || process.env.DATABASE_URL, }, readReplicas: [process.env.POSTGRES_REPLICA_URL], }) @@ -99,7 +108,7 @@ export const allDatabaseAdapters = { export const databaseAdapter = sqliteAdapter({ client: { - url: process.env.SQLITE_URL || 'file:./payloadtests.db', + url: process.env.SQLITE_URL || process.env.DATABASE_URL || 'file:./payload.db', }, autoIncrement: true })`, @@ -109,7 +118,7 @@ export const allDatabaseAdapters = { export const databaseAdapter = sqliteAdapter({ idType: 'uuid', client: { - url: process.env.SQLITE_URL || 'file:./payloadtests.db', + url: process.env.SQLITE_URL || process.env.DATABASE_URL || 'file:./payload.db', }, })`, supabase: ` @@ -118,7 +127,7 @@ export const allDatabaseAdapters = { export const databaseAdapter = postgresAdapter({ pool: { connectionString: - process.env.POSTGRES_URL || 'postgresql://postgres:postgres@127.0.0.1:54322/postgres', + process.env.POSTGRES_URL || process.env.DATABASE_URL || 'postgresql://postgres:postgres@127.0.0.1:54322/postgres', }, })`, d1: ` @@ -131,7 +140,7 @@ export const databaseAdapter = sqliteD1Adapter({ binding: global.d1 }) /** * Write to databaseAdapter.ts */ -export function generateDatabaseAdapter(dbAdapter) { +export function generateDatabaseAdapter(dbAdapter: keyof typeof allDatabaseAdapters) { const databaseAdapter = allDatabaseAdapters[dbAdapter] if (!databaseAdapter) { throw new Error(`Unknown database adapter: ${dbAdapter}`) diff --git a/test/helpers/db/mongodb-atlas/docker-compose.yml b/test/helpers/db/mongodb-atlas/docker-compose.yml new file mode 100644 index 00000000000..61d56266c78 --- /dev/null +++ b/test/helpers/db/mongodb-atlas/docker-compose.yml @@ -0,0 +1,35 @@ +# Docker Compose for MongoDB Atlas Local +# All-in-one container with Atlas Search and Vector Search built-in +# +# Usage: +# pnpm docker:mongodb-atlas:start - Start MongoDB Atlas Local +# pnpm docker:mongodb-atlas:stop - Stop +# pnpm docker:mongodb-atlas:restart:clean - Restart and remove all data +# +# For more information, see: +# https://hub.docker.com/r/mongodb/mongodb-atlas-local +# https://www.mongodb.com/docs/atlas/cli/current/atlas-cli-deploy-docker/ + +services: + mongodb-atlas: + image: mongodb/mongodb-atlas-local:latest + container_name: mongodb-atlas-payload-test + hostname: mongodb-atlas-local # Sets a fixed replica set name (used in connection string replicaSet param) + ports: + - '27018:27017' + volumes: + - mongodb_atlas_data:/data/db + environment: + - MONGODB_INITDB_ROOT_USERNAME= + - MONGODB_INITDB_ROOT_PASSWORD= + healthcheck: + test: ['CMD', 'mongosh', '--eval', "db.adminCommand('ping')"] + interval: 2s + timeout: 5s + retries: 30 + start_period: 5s + restart: unless-stopped + +volumes: + mongodb_atlas_data: + driver: local diff --git a/test/helpers/db/mongodb-atlas/run-test-connection.ts b/test/helpers/db/mongodb-atlas/run-test-connection.ts new file mode 100644 index 00000000000..b2a1422926c --- /dev/null +++ b/test/helpers/db/mongodb-atlas/run-test-connection.ts @@ -0,0 +1,13 @@ +/** + * Test script to verify MongoDB Atlas Local connection and vector search functionality + * + * Usage: + * pnpm tsx test/helpers/db/mongodb-atlas/test-connection.ts + */ + +import { testConnection } from '../mongodb/test-connection.js' + +await testConnection( + process.env.MONGODB_ATLAS_URL || + 'mongodb://localhost:27018/payload?directConnection=true&replicaSet=mongodb-atlas-local', +) diff --git a/test/helpers/db/mongodb/docker-compose-entrypoint.sh b/test/helpers/db/mongodb/docker-compose-entrypoint.sh new file mode 100755 index 00000000000..4f219070d08 --- /dev/null +++ b/test/helpers/db/mongodb/docker-compose-entrypoint.sh @@ -0,0 +1,127 @@ +#!/bin/bash +# MongoDB Community entrypoint - initializes replica set and users +# +# Why only MongoDB needs this (not Postgres or Atlas Local): +# - Replica set must be initialized AFTER mongod starts +# - Users must be created AFTER replica set is primary +# - Can't enable auth until users exist (chicken-and-egg) +# - Keyfile needs chmod 400 at runtime +# +# Sequence: start without auth → init replica set → create users → restart with auth +# Subsequent starts skip init (checks .initialized flag) +set -e + +DATA_DIR="/data/db" +KEYFILE_SRC="/etc/mongodb/keyfile" +KEYFILE="/data/db/keyfile" +INIT_FLAG="$DATA_DIR/.initialized" + +# Copy keyfile to writable location and set correct permissions +cp "$KEYFILE_SRC" "$KEYFILE" +chmod 400 "$KEYFILE" +chown mongodb:mongodb "$KEYFILE" 2>/dev/null || true + +# Check if already initialized +if [ -f "$INIT_FLAG" ]; then + echo "MongoDB already initialized, starting with auth..." + exec mongod --replSet rs0 --bind_ip_all --keyFile "$KEYFILE" \ + --setParameter searchIndexManagementHostAndPort=mongot:27028 \ + --setParameter mongotHost=mongot:27028 +fi + +echo "First run - initializing MongoDB without auth..." + +# Start MongoDB without auth in background +mongod --replSet rs0 --bind_ip_all \ + --setParameter searchIndexManagementHostAndPort=mongot:27028 \ + --setParameter mongotHost=mongot:27028 \ + --setParameter useGrpcForSearch=true \ + --setParameter skipAuthenticationToSearchIndexManagementServer=false & +MONGOD_PID=$! + +# Wait for MongoDB to start +echo "Waiting for MongoDB to start..." +for i in {1..30}; do + if mongosh --eval "db.adminCommand('ping')" 2>/dev/null; then + echo "MongoDB started" + break + fi + sleep 0.5 +done + +# Initialize replica set with hostname accessible from other containers +echo "Initializing replica set..." +mongosh --eval ' + try { + rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "mongodb:27017" }] }); + print("Replica set initiated"); + } catch(e) { + print("RS init: " + e.message); + } +' + +# Wait for primary +echo "Waiting for primary..." +for i in {1..30}; do + if mongosh --eval 'rs.isMaster().ismaster' 2>/dev/null | grep -q true; then + echo "Primary ready" + break + fi + sleep 0.5 +done + +# Create users +echo "Creating users..." +mongosh --eval ' + // Create admin user + try { + db.getSiblingDB("admin").createUser({ + user: "admin", + pwd: "adminPassword", + roles: ["root"] + }); + print("Created admin user"); + } catch(e) { + print("Admin: " + e.message); + } + + // Create mongot user with searchCoordinator role + try { + db.getSiblingDB("admin").createUser({ + user: "mongotUser", + pwd: "mongotPassword", + roles: [{ role: "searchCoordinator", db: "admin" }] + }); + print("Created mongotUser"); + } catch(e) { + print("mongotUser: " + e.message); + } + + // Create payload user for application + try { + db.getSiblingDB("admin").createUser({ + user: "payload", + pwd: "payload", + roles: ["root"] + }); + print("Created payload user"); + } catch(e) { + print("payload: " + e.message); + } +' + +# Stop MongoDB +echo "Stopping MongoDB to restart with auth..." +kill $MONGOD_PID +wait $MONGOD_PID 2>/dev/null || true + +# Mark as initialized +touch "$INIT_FLAG" + +echo "Starting MongoDB with auth enabled..." +exec mongod --replSet rs0 --bind_ip_all --keyFile "$KEYFILE" \ + --setParameter searchIndexManagementHostAndPort=mongot:27028 \ + --setParameter mongotHost=mongot:27028 \ + --setParameter useGrpcForSearch=true \ + --setParameter skipAuthenticationToSearchIndexManagementServer=false + diff --git a/test/helpers/db/mongodb/docker-compose.yml b/test/helpers/db/mongodb/docker-compose.yml new file mode 100644 index 00000000000..eb6c94189a9 --- /dev/null +++ b/test/helpers/db/mongodb/docker-compose.yml @@ -0,0 +1,80 @@ +# Docker Compose for MongoDB Community Server 8.2 with Search and Vector Search (mongot) +# This setup enables $search, $searchMeta, and $vectorSearch aggregation stages +# +# Usage: +# pnpm docker:mongodb:start - Start MongoDB with vector search +# pnpm docker:mongodb:stop - Stop MongoDB +# pnpm docker:mongodb:restart:clean - Restart and remove all data +# +# For more information, see: +# https://www.mongodb.com/docs/atlas/atlas-search/tutorial/run-local-community/ +# https://hub.docker.com/r/mongodb/mongodb-community-search + +services: + # MongoDB Community Server 8.2 with replica set and keyfile auth + # Custom entrypoint bootstraps: init replica set, create users, restart with auth + mongodb: + image: mongodb/mongodb-community-server:8.2-ubi9 + container_name: mongodb-payload-test + ports: + - '27017:27017' + volumes: + - mongodb_data:/data/db + - ./keyfile:/etc/mongodb/keyfile:ro + - ./docker-compose-entrypoint.sh:/docker-compose-entrypoint.sh:ro + entrypoint: ['/bin/bash', '/docker-compose-entrypoint.sh'] + healthcheck: + test: + [ + 'CMD', + 'mongosh', + '-u', + 'admin', + '-p', + 'adminPassword', + '--authenticationDatabase', + 'admin', + '--eval', + "db.adminCommand('ping')", + ] + interval: 2s + timeout: 5s + retries: 30 + start_period: 5s + restart: unless-stopped + + # mongot - MongoDB Community Search for $search and $vectorSearch + mongot: + image: mongodb/mongodb-community-search:latest + container_name: mongot-payload-test + depends_on: + mongodb: + condition: service_healthy + volumes: + - mongot_data:/var/lib/mongot + - ./mongot-config.yml:/etc/mongot/config-readonly.yml:ro + - ./passwordFile:/etc/mongot/secrets/passwordFile-readonly:ro + entrypoint: ['/bin/sh', '-c'] + command: + - | + # Copy files to writable location with correct permissions + cp /etc/mongot/config-readonly.yml /var/lib/mongot/config.yml + cp /etc/mongot/secrets/passwordFile-readonly /var/lib/mongot/passwordFile + chmod 400 /var/lib/mongot/passwordFile + # Update config to use the new password file location + sed -i 's|/etc/mongot/secrets/passwordFile|/var/lib/mongot/passwordFile|g' /var/lib/mongot/config.yml + # Start mongot + /mongot-community/mongot --config /var/lib/mongot/config.yml + healthcheck: + test: ['CMD-SHELL', 'curl -sf http://localhost:8080/health || exit 1'] + interval: 2s + timeout: 5s + retries: 60 + start_period: 5s + restart: unless-stopped + +volumes: + mongodb_data: + driver: local + mongot_data: + driver: local diff --git a/test/helpers/db/mongodb/keyfile b/test/helpers/db/mongodb/keyfile new file mode 100644 index 00000000000..1201dbfe132 --- /dev/null +++ b/test/helpers/db/mongodb/keyfile @@ -0,0 +1 @@ +AjncCxeB5IvLSO9Z8MYdkGuuwlqJvPNEWZ66sN7XUFqjTg6QDUtV4UBQ9UB7ggvF221FrxQB3V0nGyLd2KIrSv8SbX1sVzsnyAQDxAJm0iphN2c75gPP744rYmASaCKBqhPyb0wCOOD7K87CZ8YJUZ7EUkPUCW39sKmzzMhIE7q6HUR0U7dCa82ZV9wGdvfKVbGtLoRKZrzgHy9Iqei50s48IfOOKUKgsEvT1SWMVWFrjDo2dqOGQmJk8KZynNY42O0wPnduIQw28426mjQT2dyKgt4J3RmuY1BCrXx7n6iHm7ykADRcv8wFwZXZLi5yAArmWZqbz9HbJE4g6sJtUr4BXFyagitQ8rwVHdlU43VowQteRhKdeA0PJiTztbqmHaK8QYjEYy3m7p2onp0iFrhCltOd330G2lHBmlpMJBq3zZ6bz5gaLIPLwKUMm94mTgqsoKiuenfFPMeepT5fSDHZ8ef9ZPRY36F0pIbUmJvF6N1y0MIg10nwxZJjJ150H0JKJcgbIsAEwT2k3vl9KTlg6s8RvHTATLFiiHPPqkASx8IeJNVidxABVYdwekkc0dDWzglh5WvuN8sANenJaflwfLxhhZ1R37OmyLrKFVBPsYalYHPFWHLQDNghyMv6UebiEVh2uQlmE96DSHfHCG89bLPm05b1HIWG2g5WYUNoU2wXFt7nP4pHXBfIrzBldwEKBpwtSaGC28fFb7nMWD9OcW28Cq2uAwNI3c9klXXW5WrHJmuk \ No newline at end of file diff --git a/test/helpers/db/mongodb/mongot-config.yml b/test/helpers/db/mongodb/mongot-config.yml new file mode 100644 index 00000000000..951606785dd --- /dev/null +++ b/test/helpers/db/mongodb/mongot-config.yml @@ -0,0 +1,19 @@ +# mongot configuration for local development +syncSource: + replicaSet: + hostAndPort: 'mongodb:27017' + username: mongotUser + passwordFile: '/etc/mongot/secrets/passwordFile' +storage: + dataPath: '/var/lib/mongot' +server: + grpc: + address: '0.0.0.0:27028' + tls: + mode: 'disabled' +metrics: + enabled: false +healthCheck: + address: '0.0.0.0:8080' +logging: + verbosity: INFO diff --git a/test/helpers/db/mongodb/passwordFile b/test/helpers/db/mongodb/passwordFile new file mode 100644 index 00000000000..f6d16c22c3f --- /dev/null +++ b/test/helpers/db/mongodb/passwordFile @@ -0,0 +1 @@ +mongotPassword \ No newline at end of file diff --git a/test/helpers/db/mongodb/run-test-connection.ts b/test/helpers/db/mongodb/run-test-connection.ts new file mode 100644 index 00000000000..e4deb5811e4 --- /dev/null +++ b/test/helpers/db/mongodb/run-test-connection.ts @@ -0,0 +1,13 @@ +/** + * Test script to verify MongoDB connection, replica set, and transaction functionality + * + * Usage: + * pnpm tsx test/helpers/db/mongodb/run-test-connection.ts + */ + +import { testConnection } from './test-connection.js' + +await testConnection( + process.env.MONGODB_URL || + 'mongodb://payload:payload@localhost:27017/payload?authSource=admin&directConnection=true&replicaSet=rs0', +) diff --git a/test/helpers/db/mongodb/test-connection.ts b/test/helpers/db/mongodb/test-connection.ts new file mode 100644 index 00000000000..577d86ca7b9 --- /dev/null +++ b/test/helpers/db/mongodb/test-connection.ts @@ -0,0 +1,183 @@ +/** + * Test script to verify MongoDB connection and vector search functionality + * + * Usage: + * pnpm tsx scripts/test-mongodb-connection.ts + */ + +import mongoose from 'mongoose' + +export async function testConnection(url: string) { + console.log('🔌 Connecting to MongoDB...') + console.log(' url:', url.replace(/:[^:@]+@/, ':****@')) + + try { + await mongoose.connect(url) + console.log('✅ Connected successfully!\n') + + // Test 1: Basic ping + console.log('📍 Test 1: Ping') + const adminDb = mongoose.connection.db.admin() + const pingResult = await adminDb.ping() + console.log(' Ping result:', pingResult.ok === 1 ? 'OK' : 'FAILED') + + // Test 2: Replica set status + console.log('\n📍 Test 2: Replica Set Status') + try { + const rsStatus = await adminDb.command({ replSetGetStatus: 1 }) + const primary = rsStatus.members?.find((m: any) => m.stateStr === 'PRIMARY') + console.log(' Replica set:', rsStatus.set) + console.log(' Primary:', primary?.name || 'none') + } catch (e: any) { + console.log(' Error:', e.message) + } + + // Test 3: Transaction + console.log('\n📍 Test 3: Transaction') + const session = await mongoose.startSession() + const TestModel = + mongoose.models.TransactionTest || + mongoose.model('TransactionTest', new mongoose.Schema({ name: String })) + + await session.withTransaction(async () => { + // @ts-expect-error + await TestModel.create([{ name: 'transaction-test-' + Date.now() }], { session }) + }) + await session.endSession() + console.log(' Transaction: OK') + + // Test 4: Search Index (requires mongot) + console.log('\n📍 Test 4: Search Index') + const db = mongoose.connection.db + const searchTestColl = db.collection('search_test') + + // Insert test document + await searchTestColl.deleteMany({}) + await searchTestColl.insertOne({ + title: 'MongoDB Vector Search Test', + content: 'Testing vector search with mongot', + }) + + try { + // Create search index + await db.command({ + createSearchIndexes: 'search_test', + indexes: [ + { + name: 'text_search', + definition: { + mappings: { dynamic: true }, + }, + }, + ], + }) + console.log(' Search index created: OK') + } catch (e: any) { + if (e.message.includes('already exists')) { + console.log(' Search index: Already exists') + } else { + console.log(' Search index error:', e.message) + } + } + + // Wait for index to be ready + await new Promise((resolve) => setTimeout(resolve, 2000)) + + // Test search query + try { + const searchResults = await searchTestColl + .aggregate([{ $search: { text: { query: 'vector', path: { wildcard: '*' } } } }]) + .toArray() + console.log(' $search query: OK (found', searchResults.length, 'results)') + } catch (e: any) { + console.log(' $search query error:', e.message) + } + + // Test 5: Vector Search Index + console.log('\n📍 Test 5: Vector Search') + const vectorColl = db.collection('vector_test') + + // Insert document with embedding + await vectorColl.deleteMany({}) + const embedding = Array.from({ length: 128 }, () => Math.random()) + await vectorColl.insertOne({ + title: 'Vector Document', + embedding, + }) + + try { + // Create vector search index + await db.command({ + createSearchIndexes: 'vector_test', + indexes: [ + { + name: 'vector_index', + type: 'vectorSearch', + definition: { + fields: [ + { + type: 'vector', + path: 'embedding', + numDimensions: 128, + similarity: 'cosine', + }, + ], + }, + }, + ], + }) + console.log(' Vector index created: OK') + } catch (e: any) { + if (e.message.includes('already exists')) { + console.log(' Vector index: Already exists') + } else { + console.log(' Vector index error:', e.message) + } + } + + // Wait for index to be ready + await new Promise((resolve) => setTimeout(resolve, 2000)) + + // Test vector search query + try { + const vectorResults = await vectorColl + .aggregate([ + { + $vectorSearch: { + index: 'vector_index', + path: 'embedding', + queryVector: embedding, + numCandidates: 10, + limit: 5, + }, + }, + { + $project: { + title: 1, + score: { $meta: 'vectorSearchScore' }, + }, + }, + ]) + .toArray() + console.log(' $vectorSearch query: OK (found', vectorResults.length, 'results)') + if (vectorResults.length > 0) { + console.log(' Top result score:', vectorResults[0].score) + } + } catch (e: any) { + console.log(' $vectorSearch query error:', e.message) + } + + // Cleanup + await searchTestColl.drop().catch(() => {}) + await vectorColl.drop().catch(() => {}) + await TestModel.collection.drop().catch(() => {}) + + console.log('\n✅ All tests completed!') + } catch (error: any) { + console.error('\n❌ Error:', error.message) + process.exit(1) + } finally { + await mongoose.disconnect() + console.log('\n🔌 Disconnected.') + } +} diff --git a/test/helpers/db/postgres/docker-compose.yml b/test/helpers/db/postgres/docker-compose.yml new file mode 100644 index 00000000000..5c31eecda93 --- /dev/null +++ b/test/helpers/db/postgres/docker-compose.yml @@ -0,0 +1,41 @@ +# Docker Compose for PostgreSQL with PostGIS and pgvector +# This setup enables geospatial queries and vector search +# +# Usage: +# pnpm docker:postgres:start - Start PostgreSQL +# pnpm docker:postgres:stop - Stop PostgreSQL +# pnpm docker:postgres:restart:clean - Restart and remove all data +# +# Connection: +# Host: localhost +# Port: 5433 +# Database: payload +# User: payload +# Password: payload +# +# Connection URL: +# postgres://payload:payload@localhost:5433/payload + +services: + postgres: + image: ghcr.io/payloadcms/postgis-vector:latest + container_name: postgres-payload-test + ports: + - '5433:5432' + environment: + POSTGRES_USER: payload + POSTGRES_PASSWORD: payload + POSTGRES_DB: payload + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U payload -d payload'] + interval: 1s + timeout: 5s + retries: 30 + start_period: 2s + restart: unless-stopped + +volumes: + postgres_data: + driver: local diff --git a/test/helpers/startMemoryDB.ts b/test/helpers/startMemoryDB.ts deleted file mode 100644 index 423a3c2bfa1..00000000000 --- a/test/helpers/startMemoryDB.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { D1DatabaseAPI } from '@miniflare/d1' -import { createSQLiteDB } from '@miniflare/shared' -import dotenv from 'dotenv' -import { MongoMemoryReplSet } from 'mongodb-memory-server' - -dotenv.config() - -declare global { - // Add the custom property to the NodeJS global type - // eslint-disable-next-line no-var - var _mongoMemoryServer: MongoMemoryReplSet | undefined -} - -/** - * WARNING: This file MUST export a default function. - * @link https://jestjs.io/docs/configuration#globalsetup-string - */ -// eslint-disable-next-line no-restricted-exports -export default async () => { - if (process.env.DATABASE_URI) { - return - } - process.env.NODE_ENV = 'test' - process.env.PAYLOAD_DROP_DATABASE = 'true' - process.env.NODE_OPTIONS = '--no-deprecation' - process.env.DISABLE_PAYLOAD_HMR = 'true' - - if (process.env.PAYLOAD_DATABASE === 'd1' && !global.d1) { - process.env.PAYLOAD_DROP_DATABASE = 'false' - console.log('Starting memory D1 db...') - global.d1 = new D1DatabaseAPI(await createSQLiteDB(':memory')) - } - if ( - (!process.env.PAYLOAD_DATABASE || - ['cosmosdb', 'documentdb', 'firestore', 'mongodb'].includes(process.env.PAYLOAD_DATABASE)) && - !global._mongoMemoryServer - ) { - console.log('Starting memory db...') - const db = await MongoMemoryReplSet.create({ - replSet: { - count: 3, - dbName: 'payloadmemory', - }, - }) - - await db.waitUntilRunning() - - global._mongoMemoryServer = db - - process.env.MONGODB_MEMORY_SERVER_URI = `${global._mongoMemoryServer.getUri()}&retryWrites=true` - console.log('Started memory db') - } -} diff --git a/test/helpers/stopMemoryDB.ts b/test/helpers/stopMemoryDB.ts deleted file mode 100644 index fe482a3af15..00000000000 --- a/test/helpers/stopMemoryDB.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-disable no-restricted-exports */ -import { spawn } from 'child_process' - -/** - * WARNING: This file MUST export a default function. - * @link https://jestjs.io/docs/configuration#globalteardown-string - */ -export default function globalTeardown() { - try { - if (global._mongoMemoryServer) { - const stopScript = ` - (async () => { - await new Promise(resolve => setTimeout(resolve, 300)); - try { - if (global._mongoMemoryServer) { - await global._mongoMemoryServer.stop(); - console.log('Stopped memorydb'); - } - } catch (error) { - console.error('Error stopping memorydb:', error); - } - })(); - ` - - const child = spawn(process.execPath, ['-e', stopScript], { - detached: true, - stdio: 'ignore', - }) - - child.unref() - console.log('Spawned detached process to stop memorydb') - } - } catch (error) { - console.error('Error in globalTeardown:', error) - } -} diff --git a/test/jest.config.js b/test/jest.config.js index 06d34a82c66..6bd176af962 100644 --- a/test/jest.config.js +++ b/test/jest.config.js @@ -11,9 +11,6 @@ const customJestConfig = { testMatch: ['/**/*int.spec.ts'], setupFilesAfterEnv: ['/jest.setup.js'], - globalSetup: path.resolve(dirname, './helpers/startMemoryDB.ts'), - globalTeardown: path.resolve(dirname, './helpers/stopMemoryDB.ts'), - moduleNameMapper: { '\\.(css|scss)$': '/helpers/mocks/emptyModule.js', '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': diff --git a/test/plugin-cloud-storage/.env.emulated b/test/plugin-cloud-storage/.env.emulated index 84e6b5045ba..733abcbf147 100644 --- a/test/plugin-cloud-storage/.env.emulated +++ b/test/plugin-cloud-storage/.env.emulated @@ -1,6 +1,5 @@ # Sample creds for working locally with docker-compose -MONGODB_URI=mongodb://localhost/payload-plugin-cloud-storage PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000 PAYLOAD_SECRET=45ligj345ligj4wl5igj4lw5igj45ligj45wlijl PAYLOAD_CONFIG_PATH=config.ts diff --git a/test/storage-s3/.env.emulated b/test/storage-s3/.env.emulated deleted file mode 100644 index 84e6b5045ba..00000000000 --- a/test/storage-s3/.env.emulated +++ /dev/null @@ -1,32 +0,0 @@ -# Sample creds for working locally with docker-compose - -MONGODB_URI=mongodb://localhost/payload-plugin-cloud-storage -PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000 -PAYLOAD_SECRET=45ligj345ligj4wl5igj4lw5igj45ligj45wlijl -PAYLOAD_CONFIG_PATH=config.ts - -AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://localhost:10000/devstoreaccount1;QueueEndpoint=http://localhost:10001/devstoreaccount1; -AZURE_STORAGE_CONTAINER_NAME=az-media -AZURE_STORAGE_ALLOW_CONTAINER_CREATE=true -AZURE_STORAGE_ACCOUNT_BASEURL=http://localhost:10000/devstoreaccount1 - -S3_ENDPOINT=http://localhost:4566 -S3_ACCESS_KEY_ID=payloadAccessKey -S3_SECRET_ACCESS_KEY=alwiejglaiwhewlihgawe -S3_BUCKET=payload-bucket -S3_FORCE_PATH_STYLE=true -S3_REGION=us-east-1 - -GCS_ENDPOINT=http://localhost:4443 -GCS_PROJECT_ID=test -GCS_BUCKET=payload-bucket - -R2_ENDPOINT=https://cloudflare-generated-domain.r2.cloudflarestorage.com -R2_REGION=auto -R2_ACCESS_KEY_ID=access-key-id -R2_SECRET_ACCESS_KEY=secret-access-key -R2_BUCKET=payload-bucket -R2_FORCE_PATH_STYLE= - -PAYLOAD_DROP_DATABASE=true -PAYLOAD_PUBLIC_CLOUD_STORAGE_ADAPTER=s3 diff --git a/tools/claude-plugin/skills/payload/SKILL.md b/tools/claude-plugin/skills/payload/SKILL.md index 67e81af1066..6d6c1200b41 100644 --- a/tools/claude-plugin/skills/payload/SKILL.md +++ b/tools/claude-plugin/skills/payload/SKILL.md @@ -73,7 +73,7 @@ export default buildConfig({ outputFile: path.resolve(dirname, 'payload-types.ts'), }, db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` diff --git a/tools/claude-plugin/skills/payload/reference/ADAPTERS.md b/tools/claude-plugin/skills/payload/reference/ADAPTERS.md index e575ba73b88..04b900c6cf8 100644 --- a/tools/claude-plugin/skills/payload/reference/ADAPTERS.md +++ b/tools/claude-plugin/skills/payload/reference/ADAPTERS.md @@ -11,7 +11,7 @@ import { mongooseAdapter } from '@payloadcms/db-mongodb' export default buildConfig({ db: mongooseAdapter({ - url: process.env.DATABASE_URI, + url: process.env.DATABASE_URL, }), }) ``` @@ -24,7 +24,7 @@ import { postgresAdapter } from '@payloadcms/db-postgres' export default buildConfig({ db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, + connectionString: process.env.DATABASE_URL, }, push: false, // Don't auto-push schema changes migrationDir: './migrations', diff --git a/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md b/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md index 105a481a8aa..19d39d0061b 100644 --- a/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md +++ b/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md @@ -1296,7 +1296,7 @@ Include a `dev/` directory with a complete Payload project for local development 1. Create `dev/.env` from `.env.example`: ```bash -DATABASE_URI=mongodb://127.0.0.1/plugin-dev +DATABASE_URL=mongodb://127.0.0.1/plugin-dev PAYLOAD_SECRET=your-secret-here ``` @@ -1309,7 +1309,7 @@ import { myPlugin } from '../src/index.js' export default buildConfig({ secret: process.env.PAYLOAD_SECRET!, - db: mongooseAdapter({ url: process.env.DATABASE_URI! }), + db: mongooseAdapter({ url: process.env.DATABASE_URL! }), plugins: [ myPlugin({ collections: ['posts'], diff --git a/tools/scripts/src/build-template-with-local-pkgs.ts b/tools/scripts/src/build-template-with-local-pkgs.ts index 25e1f250314..ea86e749e98 100644 --- a/tools/scripts/src/build-template-with-local-pkgs.ts +++ b/tools/scripts/src/build-template-with-local-pkgs.ts @@ -83,7 +83,7 @@ async function main() { path.resolve(templatePath, '.env'), // Populate POSTGRES_URL just in case it's needed `PAYLOAD_SECRET=secret -DATABASE_URI=${databaseConnection} +DATABASE_URL=${databaseConnection} POSTGRES_URL=${databaseConnection} BLOB_READ_WRITE_TOKEN=vercel_blob_rw_TEST_asdf`, ) diff --git a/tools/scripts/src/generate-template-variations.ts b/tools/scripts/src/generate-template-variations.ts index 680e190261f..df686dfd80d 100644 --- a/tools/scripts/src/generate-template-variations.ts +++ b/tools/scripts/src/generate-template-variations.ts @@ -81,7 +81,7 @@ async function main() { db: 'vercel-postgres', dirname: 'with-vercel-postgres', envNames: { - // This will replace the process.env.DATABASE_URI to process.env.POSTGRES_URL + // This will replace the process.env.DATABASE_URL to process.env.POSTGRES_URL dbUri: 'POSTGRES_URL', }, sharp: false, @@ -106,7 +106,7 @@ async function main() { db: 'vercel-postgres', dirname: 'with-vercel-website', envNames: { - // This will replace the process.env.DATABASE_URI to process.env.POSTGRES_URL + // This will replace the process.env.DATABASE_URL to process.env.POSTGRES_URL dbUri: 'POSTGRES_URL', }, sharp: true, @@ -139,7 +139,7 @@ async function main() { db: 'mongodb', dirname: 'with-vercel-mongodb', envNames: { - dbUri: 'MONGODB_URI', + dbUri: 'MONGODB_URL', }, sharp: false, storage: 'vercelBlobStorage', @@ -292,7 +292,7 @@ async function main() { await configurePayloadConfig(configureArgs) log('Configuring .env.example') - // Replace DATABASE_URI with the correct env name if set + // Replace DATABASE_URL with the correct env name if set await writeEnvExample({ dbType: db, destDir, @@ -361,7 +361,7 @@ async function main() { env: { ...process.env, BLOB_READ_WRITE_TOKEN: 'vercel_blob_rw_TEST_asdf', - DATABASE_URI: process.env.POSTGRES_URL || 'postgres://localhost:5432/your-database-name', + DATABASE_URL: process.env.POSTGRES_URL || 'postgres://localhost:5432/your-database-name', PAYLOAD_SECRET: 'asecretsolongnotevensantacouldguessit', }, }) @@ -506,25 +506,25 @@ async function writeEnvExample({ if ( dbType === 'vercel-postgres' && (l.startsWith('# Or use a PG connection string') || - l.startsWith('#DATABASE_URI=postgresql://')) + l.startsWith('#DATABASE_URL=postgresql://')) ) { return false // Skip this line } return true // Keep other lines }) .map((l) => { - if (l.startsWith('DATABASE_URI')) { + if (l.startsWith('DATABASE_URL')) { if (dbType === 'mongodb') { - l = 'MONGODB_URI=mongodb://127.0.0.1/your-database-name' + l = 'MONGODB_URL=mongodb://127.0.0.1/your-database-name' } // Use db-appropriate connection string if (dbType.includes('postgres')) { - l = 'DATABASE_URI=postgresql://127.0.0.1:5432/your-database-name' + l = 'DATABASE_URL=postgresql://127.0.0.1:5432/your-database-name' } - // Replace DATABASE_URI with the correct env name if set + // Replace DATABASE_URL with the correct env name if set if (envNames?.dbUri) { - l = l.replace('DATABASE_URI', envNames.dbUri) + l = l.replace('DATABASE_URL', envNames.dbUri) } } return l From 10302c765fd8d86480b6a512a28869bcfa893ae1 Mon Sep 17 00:00:00 2001 From: German Jablonski <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 19 Dec 2025 15:22:03 +0000 Subject: [PATCH 29/67] feat: modular dashboards - widgets (#13683) [RFC Here](https://github.com/payloadcms/payload/discussions/11862). You can test the feature by running `pnpm dev dashboard` on this branch.
Old (obsolete) example See the [comment below](https://github.com/payloadcms/payload/pull/13683#issuecomment-3581457901) explaining the change in approach we took https://github.com/user-attachments/assets/96157f83-c5d7-4350-9f31-c014daedb2a8
### New demo https://github.com/user-attachments/assets/6c08d8d6-c989-4845-b56f-6d3fbd30b1af ## Future Work The following improvements are planned but will be added in the future: - fields: You'll be able to define `fields` that a widget receives, which will serve as props in the component. Why might this be useful? Imagine a chart widget that can have a weekly, daily, or yearly view. Or a "count" widget that shows how many documents there are in a collection (the collection could be a field). - A11y (EDITED): Okay, I finally went the extra mile here, and you can reorder and resize it with the keyboard. The screen reader works, although there's room for improvement. - Dashboard presets: we're planning to add the ability to create and share dashboard presets, similar to how [query presets](https://payloadcms.com/docs/query-presets/overview) work today. For example, you could build dashboards that adjust based on a variable, such as a "daily, weekly, or monthly" interval. You could also create dashboards tailored to different focus areas, like "marketing, sales, or product." --- .github/workflows/main.yml | 2 + docs/custom-components/custom-views.mdx | 5 + docs/custom-components/dashboard.mdx | 153 +++++++ docs/custom-components/root-components.mdx | 12 + packages/next/package.json | 2 + .../next/src/utilities/getVisibleEntities.ts | 18 - .../src/utilities/handleServerFunctions.ts | 4 + .../ModularDashboard/DashboardStepNav.tsx | 128 ++++++ .../Default/ModularDashboard/index.client.tsx | 371 ++++++++++++++++ .../Default/ModularDashboard/index.scss | 316 +++++++++++++ .../Default/ModularDashboard/index.tsx | 111 +++++ .../renderWidget/RenderWidget.tsx | 82 ++++ .../renderWidget/getDefaultLayoutServerFn.ts | 76 ++++ .../renderWidget/renderWidgetServerFn.ts | 100 +++++ .../ModularDashboard/useDashboardLayout.ts | 206 +++++++++ .../utils/collisionDetection.ts | 40 ++ .../Default/ModularDashboard/utils/sensors.ts | 319 ++++++++++++++ .../src/views/Dashboard/Default/index.tsx | 213 ++------- packages/next/src/views/Dashboard/index.tsx | 84 +--- packages/next/src/views/NotFound/index.tsx | 2 +- packages/next/src/views/Root/index.tsx | 2 +- packages/payload/src/admin/types.ts | 2 + packages/payload/src/admin/views/dashboard.ts | 12 + .../bin/generateImportMap/iterateConfig.ts | 6 + packages/payload/src/config/client.ts | 20 +- packages/payload/src/config/sanitize.ts | 14 +- packages/payload/src/config/types.ts | 52 +++ packages/payload/src/index.ts | 1 + packages/translations/src/clientKeys.ts | 4 + packages/translations/src/languages/ar.ts | 5 + packages/translations/src/languages/az.ts | 5 + packages/translations/src/languages/bg.ts | 5 + packages/translations/src/languages/bnBd.ts | 5 + packages/translations/src/languages/bnIn.ts | 5 + packages/translations/src/languages/ca.ts | 5 + packages/translations/src/languages/cs.ts | 5 + packages/translations/src/languages/da.ts | 5 + packages/translations/src/languages/de.ts | 5 + packages/translations/src/languages/en.ts | 5 + packages/translations/src/languages/es.ts | 5 + packages/translations/src/languages/et.ts | 5 + packages/translations/src/languages/fa.ts | 5 + packages/translations/src/languages/fr.ts | 5 + packages/translations/src/languages/he.ts | 5 + packages/translations/src/languages/hr.ts | 5 + packages/translations/src/languages/hu.ts | 5 + packages/translations/src/languages/hy.ts | 5 + packages/translations/src/languages/id.ts | 5 + packages/translations/src/languages/is.ts | 5 + packages/translations/src/languages/it.ts | 5 + packages/translations/src/languages/ja.ts | 5 + packages/translations/src/languages/ko.ts | 5 + packages/translations/src/languages/lt.ts | 5 + packages/translations/src/languages/lv.ts | 5 + packages/translations/src/languages/my.ts | 5 + packages/translations/src/languages/nb.ts | 5 + packages/translations/src/languages/nl.ts | 5 + packages/translations/src/languages/pl.ts | 5 + packages/translations/src/languages/pt.ts | 5 + packages/translations/src/languages/ro.ts | 5 + packages/translations/src/languages/rs.ts | 5 + .../translations/src/languages/rsLatin.ts | 5 + packages/translations/src/languages/ru.ts | 5 + packages/translations/src/languages/sk.ts | 5 + packages/translations/src/languages/sl.ts | 5 + packages/translations/src/languages/sv.ts | 5 + packages/translations/src/languages/ta.ts | 5 + packages/translations/src/languages/th.ts | 5 + packages/translations/src/languages/tr.ts | 5 + packages/translations/src/languages/uk.ts | 5 + packages/translations/src/languages/vi.ts | 5 + packages/translations/src/languages/zh.ts | 5 + packages/translations/src/languages/zhTw.ts | 5 + packages/ui/src/elements/AppHeader/index.scss | 1 - .../ItemsDrawer/ItemSearch/index.scss | 38 ++ .../elements/ItemsDrawer/ItemSearch/index.tsx | 38 ++ .../ui/src/elements/ItemsDrawer/index.scss | 102 +++++ .../ui/src/elements/ItemsDrawer/index.tsx | 226 ++++++++++ packages/ui/src/elements/Link/index.tsx | 9 +- packages/ui/src/elements/StepNav/context.tsx | 10 +- packages/ui/src/elements/StepNav/index.scss | 1 - packages/ui/src/exports/client/index.ts | 1 + packages/ui/src/exports/rsc/index.ts | 1 + packages/ui/src/exports/shared/index.ts | 3 + .../src/providers/RouteTransition/index.tsx | 7 +- packages/ui/src/scss/app.scss | 12 + packages/ui/src/utilities/getGlobalData.ts | 61 +++ packages/ui/src/utilities/getNavGroups.ts | 50 +++ .../ui/src/utilities/getVisibleEntities.ts | 25 ++ packages/ui/src/utilities/groupNavItems.ts | 3 + .../src/widgets/CollectionCards}/index.scss | 7 +- .../ui/src/widgets/CollectionCards/index.tsx | 141 ++++++ payload-types.ts | 162 ++++++- pnpm-lock.yaml | 415 ++++++++++++++++-- test/admin/e2e/general/e2e.spec.ts | 12 +- test/dashboard/collections/Events.ts | 90 ++++ test/dashboard/collections/Revenue.ts | 56 +++ test/dashboard/collections/Tickets.ts | 69 +++ .../components/BeforeOrAfterDashboard.tsx | 8 + test/dashboard/components/Count.tsx | 116 +++++ test/dashboard/components/Private.tsx | 73 +++ test/dashboard/components/Revenue.tsx | 156 +++++++ test/dashboard/config.ts | 96 ++++ test/dashboard/e2e.spec.ts | 202 +++++++++ test/dashboard/seed.ts | 73 +++ test/dashboard/tsconfig.eslint.json | 13 + test/dashboard/tsconfig.json | 3 + test/dashboard/utils.ts | 289 ++++++++++++ test/helpers.ts | 11 +- test/locked-documents/e2e.spec.ts | 14 +- test/package.json | 3 + tsconfig.base.json | 130 ++++-- 112 files changed, 4934 insertions(+), 370 deletions(-) create mode 100644 docs/custom-components/dashboard.mdx delete mode 100644 packages/next/src/utilities/getVisibleEntities.ts create mode 100644 packages/next/src/views/Dashboard/Default/ModularDashboard/DashboardStepNav.tsx create mode 100644 packages/next/src/views/Dashboard/Default/ModularDashboard/index.client.tsx create mode 100644 packages/next/src/views/Dashboard/Default/ModularDashboard/index.scss create mode 100644 packages/next/src/views/Dashboard/Default/ModularDashboard/index.tsx create mode 100644 packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/RenderWidget.tsx create mode 100644 packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.ts create mode 100644 packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.ts create mode 100644 packages/next/src/views/Dashboard/Default/ModularDashboard/useDashboardLayout.ts create mode 100644 packages/next/src/views/Dashboard/Default/ModularDashboard/utils/collisionDetection.ts create mode 100644 packages/next/src/views/Dashboard/Default/ModularDashboard/utils/sensors.ts create mode 100644 packages/payload/src/admin/views/dashboard.ts create mode 100644 packages/ui/src/elements/ItemsDrawer/ItemSearch/index.scss create mode 100644 packages/ui/src/elements/ItemsDrawer/ItemSearch/index.tsx create mode 100644 packages/ui/src/elements/ItemsDrawer/index.scss create mode 100644 packages/ui/src/elements/ItemsDrawer/index.tsx create mode 100644 packages/ui/src/utilities/getGlobalData.ts create mode 100644 packages/ui/src/utilities/getNavGroups.ts create mode 100644 packages/ui/src/utilities/getVisibleEntities.ts rename packages/{next/src/views/Dashboard/Default => ui/src/widgets/CollectionCards}/index.scss (91%) create mode 100644 packages/ui/src/widgets/CollectionCards/index.tsx create mode 100644 test/dashboard/collections/Events.ts create mode 100644 test/dashboard/collections/Revenue.ts create mode 100644 test/dashboard/collections/Tickets.ts create mode 100644 test/dashboard/components/BeforeOrAfterDashboard.tsx create mode 100644 test/dashboard/components/Count.tsx create mode 100644 test/dashboard/components/Private.tsx create mode 100644 test/dashboard/components/Revenue.tsx create mode 100644 test/dashboard/config.ts create mode 100644 test/dashboard/e2e.spec.ts create mode 100644 test/dashboard/seed.ts create mode 100644 test/dashboard/tsconfig.eslint.json create mode 100644 test/dashboard/tsconfig.json create mode 100644 test/dashboard/utils.ts diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b17a14d8660..66ce2bd001b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -233,6 +233,7 @@ jobs: - auth - auth-basic - bulk-edit + - dashboard - joins - field-error-states - fields-relationship @@ -387,6 +388,7 @@ jobs: - auth - auth-basic - bulk-edit + - dashboard - joins - field-error-states - fields-relationship diff --git a/docs/custom-components/custom-views.mdx b/docs/custom-components/custom-views.mdx index 0bb4254faa6..bb6e41141fa 100644 --- a/docs/custom-components/custom-views.mdx +++ b/docs/custom-components/custom-views.mdx @@ -46,6 +46,11 @@ const config = buildConfig({ }) ``` + + **Note:** The dashboard is a special case, where in addition to replacing the + default view, [you can add widgets modularly](../custom-components/dashboard). + + For more granular control, pass a configuration object instead. Payload exposes the following properties for each view: | Property | Description | diff --git a/docs/custom-components/dashboard.mdx b/docs/custom-components/dashboard.mdx new file mode 100644 index 00000000000..18f926d8b38 --- /dev/null +++ b/docs/custom-components/dashboard.mdx @@ -0,0 +1,153 @@ +--- +title: Dashboard Widgets +label: Dashboard +order: 45 +desc: Create custom dashboard widgets to display data, analytics, or any other content in the Payload Admin Panel. +keywords: dashboard, widgets, custom components, admin, React +--- + + + This new Modular Dashboard is an experimental feature and may change in future + releases. Use at your own risk. + + +The Dashboard is the first page users see when they log into the Payload Admin Panel. By default, it displays cards with the collections and globals. You can customize the dashboard by adding **widgets** - modular components that can display data, analytics, or any other content. + +One of the coolest things about widgets is that each plugin can define its own. Some examples: + +- Analytics +- Error Reporting +- Number of documents that meet a certain filter +- Jobs recently executed + +### Defining Widgets + +Define widgets in your Payload config using the `admin.dashboard.widgets` property: + +```ts +import { buildConfig } from 'payload' + +export default buildConfig({ + // ... + admin: { + dashboard: { + widgets: [ + { + slug: 'user-stats', + ComponentPath: './components/UserStats.tsx#default', + minWidth: 'medium', + maxWidth: 'full', + }, + { + slug: 'revenue-chart', + ComponentPath: './components/RevenueChart.tsx#default', + minWidth: 'small', + }, + ], + }, + }, +}) +``` + +### Widget Configuration + +| Property | Type | Description | +| ------------------ | ------------- | -------------------------------------------------------------------- | +| `slug` \* | `string` | Unique identifier for the widget | +| `ComponentPath` \* | `string` | Path to the widget component (supports `#` syntax for named exports) | +| `minWidth` | `WidgetWidth` | Minimum width the widget can be resized to (default: `'x-small'`) | +| `maxWidth` | `WidgetWidth` | Maximum width the widget can be resized to (default: `'full'`) | + +**WidgetWidth Values:** `'x-small'` \| `'small'` \| `'medium'` \| `'large'` \| `'x-large'` \| `'full'` + +### Creating a Widget Component + +Widgets are React Server Components that receive `WidgetServerProps`: + +```tsx +import type { WidgetServerProps } from 'payload' + +export default async function UserStatsWidget({ req }: WidgetServerProps) { + const { payload } = req + + // Fetch data server-side + const userCount = await payload.count({ collection: 'users' }) + + return ( +
+

Total Users

+

+ {userCount.totalDocs} +

+
+ ) +} +``` + +For visual consistency with the Payload UI, we recommend: + +1. Using the `card` class for your root element, unless you don't want it to have a background color. +2. Using our theme variables for backgrounds and text colors. For example, use `var(--theme-elevation-0)` for backgrounds and `var(--theme-text)` for text colors. + +### Default Layout + +Control the initial dashboard layout with the `defaultLayout` property: + +```ts +export default buildConfig({ + admin: { + dashboard: { + defaultLayout: ({ req }) => { + // Customize layout based on user role or other factors + const isAdmin = req.user?.roles?.includes('admin') + + return [ + { widgetSlug: 'collections', width: 'full' }, + { widgetSlug: 'user-stats', width: isAdmin ? 'medium' : 'full' }, + { widgetSlug: 'revenue-chart', width: 'full' }, + ] + }, + widgets: [ + // ... widget definitions + ], + }, + }, +}) +``` + +The `defaultLayout` function receives the request object and should return an array of `WidgetInstance` objects. + +#### WidgetInstance Type + +| Property | Type | Description | +| --------------- | ------------- | ----------------------------------------------- | +| `widgetSlug` \* | `string` | Slug of the widget to display | +| `width` | `WidgetWidth` | Initial width of the widget (default: minWidth) | + + + **Tip:** Users can customize their dashboard layout, which is saved to their + preferences. The `defaultLayout` is only used for first-time visitors or after + a layout reset. + + +### Built-in Widgets + +Payload includes a built-in `collections` widget that displays collection and global cards. + +If you don't define a `defaultLayout`, the collections widget will be automatically included in your dashboard. + +### User Customization + +{/* TODO: maybe a good GIF here? */} + +Users can customize their dashboard by: + +1. Clicking the dashboard dropdown in the breadcrumb +2. Selecting "Edit Dashboard" +3. Adding widgets via the "Add +" button +4. Resizing widgets using the width dropdown on each widget +5. Reordering widgets via drag-and-drop +6. Deleting widgets using the delete button +7. Saving changes or canceling to revert + +Users can also reset their dashboard to the default layout using the "Reset Layout" option. diff --git a/docs/custom-components/root-components.mdx b/docs/custom-components/root-components.mdx index 70bcc489970..03cadde9aaf 100644 --- a/docs/custom-components/root-components.mdx +++ b/docs/custom-components/root-components.mdx @@ -127,6 +127,12 @@ export default function MyBeforeDashboardComponent() { } ``` + + **Note:** You can also set [Dashboard Widgets](../custom-components/dashboard) + in the `admin.dashboard` property, or replace the entire [Dashboard + View](../custom-components/dashboard) with your own. + + ### afterDashboard Similar to `beforeDashboard`, the `afterDashboard` property allows you to inject Custom Components into the built-in Dashboard, _after_ the default dashboard contents. @@ -156,6 +162,12 @@ export default function MyAfterDashboardComponent() { } ``` + + **Note:** You can also set [Dashboard Widgets](../custom-components/dashboard) + in the `admin.dashboard` property, or replace the entire [Dashboard + View](../custom-components/dashboard) with your own. + + ### beforeLogin The `beforeLogin` property allows you to inject Custom Components into the built-in Login view, _before_ the default login form. diff --git a/packages/next/package.json b/packages/next/package.json index 80d5a58e433..cec82fb2914 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -109,6 +109,8 @@ }, "dependencies": { "@dnd-kit/core": "6.0.8", + "@dnd-kit/modifiers": "9.0.0", + "@dnd-kit/sortable": "7.0.2", "@payloadcms/graphql": "workspace:*", "@payloadcms/translations": "workspace:*", "@payloadcms/ui": "workspace:*", diff --git a/packages/next/src/utilities/getVisibleEntities.ts b/packages/next/src/utilities/getVisibleEntities.ts deleted file mode 100644 index 1b47202dbe9..00000000000 --- a/packages/next/src/utilities/getVisibleEntities.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { PayloadRequest, VisibleEntities } from 'payload' - -import { isEntityHidden } from 'payload' - -export function getVisibleEntities({ req }: { req: PayloadRequest }): VisibleEntities { - return { - collections: req.payload.config.collections - .map(({ slug, admin: { hidden } }) => - !isEntityHidden({ hidden, user: req.user }) ? slug : null, - ) - .filter(Boolean), - globals: req.payload.config.globals - .map(({ slug, admin: { hidden } }) => - !isEntityHidden({ hidden, user: req.user }) ? slug : null, - ) - .filter(Boolean), - } -} diff --git a/packages/next/src/utilities/handleServerFunctions.ts b/packages/next/src/utilities/handleServerFunctions.ts index 79d4e2b3fdb..9534493fef0 100644 --- a/packages/next/src/utilities/handleServerFunctions.ts +++ b/packages/next/src/utilities/handleServerFunctions.ts @@ -6,6 +6,8 @@ import { buildTableStateHandler } from '@payloadcms/ui/utilities/buildTableState import { getFolderResultsComponentAndDataHandler } from '@payloadcms/ui/utilities/getFolderResultsComponentAndData' import { schedulePublishHandler } from '@payloadcms/ui/utilities/schedulePublishHandler' +import { getDefaultLayoutHandler } from '../views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.js' +import { renderWidgetHandler } from '../views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.js' import { renderDocumentHandler } from '../views/Document/handleServerFunction.js' import { renderDocumentSlotsHandler } from '../views/Document/renderDocumentSlots.js' import { renderListHandler } from '../views/List/handleServerFunction.js' @@ -15,11 +17,13 @@ import { slugifyHandler } from './slugify.js' const baseServerFunctions: Record> = { 'copy-data-from-locale': copyDataFromLocaleHandler, 'form-state': buildFormStateHandler, + 'get-default-layout': getDefaultLayoutHandler, 'get-folder-results-component-and-data': getFolderResultsComponentAndDataHandler, 'render-document': renderDocumentHandler, 'render-document-slots': renderDocumentSlotsHandler, 'render-field': _internal_renderFieldHandler, 'render-list': renderListHandler, + 'render-widget': renderWidgetHandler, 'schedule-publish': schedulePublishHandler, slugify: slugifyHandler, 'table-state': buildTableStateHandler, diff --git a/packages/next/src/views/Dashboard/Default/ModularDashboard/DashboardStepNav.tsx b/packages/next/src/views/Dashboard/Default/ModularDashboard/DashboardStepNav.tsx new file mode 100644 index 00000000000..2567c2c7a12 --- /dev/null +++ b/packages/next/src/views/Dashboard/Default/ModularDashboard/DashboardStepNav.tsx @@ -0,0 +1,128 @@ +'use client' +import type { ClientWidget } from 'payload' + +import { + Button, + DrawerToggler, + ItemsDrawer, + type ReactSelectOption as Option, + ReactSelect, + useStepNav, + useTranslation, +} from '@payloadcms/ui' +import { useEffect, useId } from 'react' + +export function DashboardStepNav({ + addWidget, + cancel, + isEditing, + resetLayout, + saveLayout, + setIsEditing, + widgets, +}: { + addWidget: (slug: string) => void + cancel: () => void + isEditing: boolean + resetLayout: () => Promise + saveLayout: () => Promise + setIsEditing: (isEditing: boolean) => void + widgets: ClientWidget[] +}) { + const { t } = useTranslation() + const { setStepNav } = useStepNav() + const uuid = useId() + const drawerSlug = `widgets-drawer-${uuid}` + + useEffect(() => { + setStepNav([ + { + label: ( + setIsEditing(true)} + onResetLayout={resetLayout} + onSaveChanges={saveLayout} + widgetsDrawerSlug={drawerSlug} + /> + ), + }, + ]) + }, [isEditing, drawerSlug, cancel, resetLayout, saveLayout, setIsEditing, setStepNav]) + + return ( + <> + {isEditing && ( + addWidget(widget.slug)} + searchPlaceholder={t('dashboard:searchWidgets')} + title={t('dashboard:addWidget')} + /> + )} + + ) +} + +export function DashboardBreadcrumbDropdown(props: { + isEditing: boolean + onCancel: () => void + onEditClick: () => void + onResetLayout: () => void + onSaveChanges: () => void + widgetsDrawerSlug: string +}) { + const { isEditing, onCancel, onEditClick, onResetLayout, onSaveChanges, widgetsDrawerSlug } = + props + if (isEditing) { + return ( +
+ Editing Dashboard +
+ + + + + +
+
+ ) + } + + const options = [ + { label: 'Edit Dashboard', value: 'edit' }, + { label: 'Reset Layout', value: 'reset' }, + ] + + const handleChange = (selectedOption: Option | Option[]) => { + // Since isMulti is false, we expect a single Option + const option = Array.isArray(selectedOption) ? selectedOption[0] : selectedOption + + if (option?.value === 'edit') { + onEditClick() + } else if (option?.value === 'reset') { + onResetLayout() + } + } + + return ( + + ) +} diff --git a/packages/next/src/views/Dashboard/Default/ModularDashboard/index.client.tsx b/packages/next/src/views/Dashboard/Default/ModularDashboard/index.client.tsx new file mode 100644 index 00000000000..bde852e771f --- /dev/null +++ b/packages/next/src/views/Dashboard/Default/ModularDashboard/index.client.tsx @@ -0,0 +1,371 @@ +'use client' + +import type { Modifier } from '@dnd-kit/core' +import type { ClientWidget, WidgetWidth } from 'payload' + +import { DndContext, DragOverlay, useDraggable, useDroppable } from '@dnd-kit/core' +import { snapCenterToCursor } from '@dnd-kit/modifiers' +import { ChevronIcon, Popup, PopupList, useTranslation, XIcon } from '@payloadcms/ui' +import React, { useMemo, useState } from 'react' + +/** + * Custom modifier that only applies snapCenterToCursor for pointer events. + * During keyboard navigation, we handle positioning ourselves via the coordinate getter. + */ +const snapCenterToCursorOnlyForPointer: Modifier = (args) => { + const { activatorEvent } = args + + // Only apply snap for pointer events (mouse/touch), not keyboard + // Check activatorEvent.type since KeyboardEvent may not exist on server + if (activatorEvent && 'key' in activatorEvent) { + return args.transform + } + + return snapCenterToCursor(args) +} + +import { DashboardStepNav } from './DashboardStepNav.js' +import { useDashboardLayout } from './useDashboardLayout.js' +import { closestInXAxis } from './utils/collisionDetection.js' +import { useDashboardSensors } from './utils/sensors.js' + +export type WidgetItem = { + id: string + maxWidth: WidgetWidth + minWidth: WidgetWidth + width: WidgetWidth +} + +export type WidgetInstanceClient = { + component: React.ReactNode + item: WidgetItem +} + +export type DropTargetWidget = { + position: 'after' | 'before' + widget: WidgetInstanceClient +} | null + +/* eslint-disable perfectionist/sort-objects */ +const WIDTH_TO_PERCENTAGE = { + 'x-small': 25, + small: (1 / 3) * 100, + medium: 50, + large: (2 / 3) * 100, + 'x-large': 75, + full: 100, +} as const + +export function ModularDashboardClient({ + clientLayout: initialLayout, + widgets, +}: { + clientLayout: WidgetInstanceClient[] + widgets: ClientWidget[] +}) { + const { t } = useTranslation() + const { + addWidget, + cancel, + cancelModal, + currentLayout, + deleteWidget, + isEditing, + moveWidget, + resetLayout, + resizeWidget, + saveLayout, + setIsEditing, + } = useDashboardLayout(initialLayout) + + const [activeDragId, setActiveDragId] = useState(null) + const sensors = useDashboardSensors() + + return ( +
+ { + setActiveDragId(null) + }} + onDragEnd={(event) => { + if (!event.over) { + setActiveDragId(null) + return + } + const droppableId = event.over.id as string + const i = droppableId.lastIndexOf('-') + const slug = droppableId.slice(0, i) + const position = droppableId.slice(i + 1) + + if (slug === event.active.id) { + return + } + + const moveFromIndex = currentLayout?.findIndex( + (widget) => widget.item.id === event.active.id, + ) + let moveToIndex = currentLayout?.findIndex((widget) => widget.item.id === slug) + if (moveFromIndex < moveToIndex) { + moveToIndex-- + } + if (position === 'after') { + moveToIndex++ + } + moveWidget({ moveFromIndex, moveToIndex }) + setActiveDragId(null) + }} + onDragStart={(event) => { + setActiveDragId(event.active.id as string) + }} + sensors={sensors} + > +
+ {currentLayout?.length === 0 && ( +
+

+ There are no widgets on your dashboard. You can add them from the "Dashboard" menu + located in the top bar. +

+
+ )} + {currentLayout?.map((widget, _index) => ( + + +
+
+ {widget.component} +
+ {isEditing && ( +
e.stopPropagation()} + > + resizeWidget(widget.item.id, width)} + /> + +
+ )} +
+
+
+ ))} + + {activeDragId + ? (() => { + const draggedWidget = currentLayout?.find( + (widget) => widget.item.id === activeDragId, + ) + return draggedWidget ? ( +
+
+
{draggedWidget.component}
+
+
+ ) : null + })() + : null} +
+
+
+ + {cancelModal} +
+ ) +} + +function WidgetWidthDropdown({ + currentWidth, + maxWidth, + minWidth, + onResize, +}: { + currentWidth: WidgetWidth + maxWidth: WidgetWidth + minWidth: WidgetWidth + onResize: (width: WidgetWidth) => void +}) { + // Filter options based on minWidth and maxWidth + const validOptions = useMemo(() => { + const minPercentage = WIDTH_TO_PERCENTAGE[minWidth] + const maxPercentage = WIDTH_TO_PERCENTAGE[maxWidth] + + return Object.entries(WIDTH_TO_PERCENTAGE) + .map(([key, value]) => ({ + width: key as WidgetWidth, + percentage: value, + })) + .filter((option) => option.percentage >= minPercentage && option.percentage <= maxPercentage) + }, [minWidth, maxWidth]) + + const isDisabled = validOptions.length <= 1 + + return ( + e.stopPropagation()} + type="button" + > + {currentWidth} + + + } + buttonType="custom" + disabled={isDisabled} + render={({ close }) => ( + + {validOptions.map((option) => { + const isSelected = option.width === currentWidth + return ( + { + onResize(option.width) + close() + }} + > + {option.width} + + {option.percentage.toFixed(0)}% + + + ) + })} + + )} + size="small" + verticalAlign="bottom" + /> + ) +} + +function DraggableItem(props: { + children: React.ReactNode + disabled?: boolean + id: string + style?: React.CSSProperties + width: WidgetWidth +}) { + const { attributes, isDragging, listeners, setNodeRef } = useDraggable({ + id: props.id, + disabled: props.disabled, + }) + + const mergedStyles: React.CSSProperties = { + ...props.style, + opacity: isDragging ? 0.3 : 1, + position: 'relative', + } + + // Only apply draggable attributes and listeners when not disabled + // to prevent disabling interactive elements inside the widget + const draggableProps = props.disabled ? {} : { ...listeners, ...attributes } + + return ( +
+ +
+ {props.children} +
+ +
+ ) +} + +function DroppableItem({ id, position }: { id: string; position: 'after' | 'before' }) { + const { setNodeRef, isOver } = useDroppable({ id: `${id}-${position}`, data: { position } }) + + return ( +
+ ) +} diff --git a/packages/next/src/views/Dashboard/Default/ModularDashboard/index.scss b/packages/next/src/views/Dashboard/Default/ModularDashboard/index.scss new file mode 100644 index 00000000000..060be5f9bdf --- /dev/null +++ b/packages/next/src/views/Dashboard/Default/ModularDashboard/index.scss @@ -0,0 +1,316 @@ +@import '~@payloadcms/ui/scss'; + +@layer payload-default { + .modular-dashboard { + .widget-content { + height: 100%; + } + + // In mobile, make the widget full width and hide the size button. + @media (max-width: 768px) { + .widget { + width: 100% !important; + } + + .widget-wrapper__size-btn { + display: none; + } + } + + &.editing { + .widget-content { + user-select: none; + -webkit-user-select: none; + pointer-events: none; + } + + .draggable { + cursor: grab; + } + } + + .drag-overlay { + pointer-events: none; + user-select: none; + } + + &__empty { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; + padding: 24px; + } + } + + // Apply grabbing cursor to body when drag-overlay is present + body:has(.drag-overlay) * { + cursor: grabbing; + } + + .widget-wrapper__controls { + opacity: 0; + transition: opacity 0.2s ease; + } + + .widget:focus, + .widget:focus-within { + .widget-wrapper__controls { + opacity: 1; + } + } + + // This is used to highlight a newly added widget. + @keyframes widget-highlight { + 0% { + box-shadow: 0 0 0 3px rgba(255, 208, 0, 0.9); + } + 100% { + box-shadow: 0 0 0 3px rgba(255, 208, 0, 0); + } + } + + .widget { + &--highlight { + animation: widget-highlight 1.5s ease-out forwards; + border-radius: 8px; + } + } + + .widget-wrapper { + position: relative; + height: 100%; + width: 100%; + + &--editing { + .widget-wrapper__controls { + // opacity: 0; + transition: opacity 0.2s ease; + } + + &:hover { + .widget-wrapper__controls { + opacity: 1; + } + } + } + + &__controls { + position: absolute; + top: 16px; + right: 16px; + z-index: 10; + + display: flex; + align-items: center; + gap: 8px; + } + + &__delete-btn { + display: flex; + align-items: center; + justify-content: center; + + width: 28px; + height: 28px; + + background: var(--theme-text); + border: none; + border-radius: 4px; + cursor: pointer; + + transition: all 0.2s ease; + + .icon { + width: 16px; + height: 16px; + + .stroke { + stroke: var(--theme-elevation-0); + stroke-width: 2; + } + } + + &:hover { + background: var(--theme-elevation-800); + } + + &:active { + background: var(--theme-elevation-900); + } + + svg { + pointer-events: none; + } + } + + &__size-btn { + display: flex; + align-items: center; + gap: 6px; + padding: 6px 10px; + min-width: auto; + height: 28px; + + background: var(--theme-text); + border: none; + border-radius: 4px; + cursor: pointer; + + transition: all 0.2s ease; + + font-size: 12px; + font-weight: 500; + color: var(--theme-elevation-0); + white-space: nowrap; + + .icon { + width: 12px; + height: 12px; + flex-shrink: 0; + + .stroke { + stroke: var(--theme-elevation-0); + stroke-width: 2; + } + } + + &:hover { + background: var(--theme-elevation-800); + } + + &:active { + background: var(--theme-elevation-900); + } + + &:disabled { + opacity: 0.5; + cursor: not-allowed; + + &:hover { + background: var(--theme-text); + } + } + + svg { + pointer-events: none; + } + } + + &__size-btn-percentage { + font-size: 12px; + margin-left: auto; + color: var(--theme-elevation-500); + } + } + + // Since popup uses portal and renders to body, we need global styles + // for the size selection buttons in widget wrappers + .popup-button-list:has(.widget-wrapper__size-btn-label) { + .popup__scroll-container { + padding: 0; + } + } + + .popup__content:has(.widget-wrapper__size-btn-label) { + padding: 5px; + box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; + } + + .popup-button-list__button:has(.widget-wrapper__size-btn-label) { + display: flex !important; + align-items: center !important; + gap: 20px; + + .widget-wrapper__size-btn-label { + flex: 0 0 auto; + } + + .widget-wrapper__size-btn-percentage { + margin-left: auto !important; + } + } + + .step-nav { + .dashboard-breadcrumb-dropdown { + &__editing { + align-items: center; + display: flex !important; + gap: 12px; + } + + &__actions { + display: flex !important; + gap: 8px; + } + } + + .dashboard-breadcrumb-select { + position: relative; + z-index: 10; + + .rs__control { + background: transparent; + border: none; + box-shadow: none; + padding: 0; + cursor: pointer; + + &:hover { + background: transparent; + } + } + + .rs__indicator-separator { + display: none; + } + + .rs__dropdown-indicator { + padding: 0 4px; + } + + .rs__menu { + position: absolute; + top: 100%; + left: 0; + min-width: 150px; + z-index: 9999; + border-radius: 4px; + padding: 5px; + box-shadow: + 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); + } + + .rs__menu-list { + padding: 0; + } + + .rs__option { + padding: 4px 8px; + border-radius: 3px; + margin: 0; + } + } + + .rs__control { + box-shadow: none !important; + cursor: pointer !important; + } + + .drawer-toggler--unstyled { + background: transparent; + border: none; + margin: 0; + padding: 0; + outline: none; + box-shadow: none; + + &:hover, + &:focus { + background: transparent; + } + } + } +} diff --git a/packages/next/src/views/Dashboard/Default/ModularDashboard/index.tsx b/packages/next/src/views/Dashboard/Default/ModularDashboard/index.tsx new file mode 100644 index 00000000000..382e7dce9f6 --- /dev/null +++ b/packages/next/src/views/Dashboard/Default/ModularDashboard/index.tsx @@ -0,0 +1,111 @@ +import type { TFunction } from '@payloadcms/translations' +import type { + BasePayload, + ClientWidget, + DashboardConfig, + PayloadRequest, + TypedUser, + Widget, + WidgetInstance, + WidgetServerProps, +} from 'payload' + +import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' +import React from 'react' + +import type { DashboardViewServerProps } from '../index.js' +import type { WidgetInstanceClient, WidgetItem } from './index.client.js' + +import { getPreferences } from '../../../../utilities/getPreferences.js' +import { ModularDashboardClient } from './index.client.js' +import './index.scss' + +type ServerLayout = WidgetInstanceClient[] + +export async function ModularDashboard(props: DashboardViewServerProps) { + const { defaultLayout = [], widgets = [] } = props.payload.config.admin.dashboard || {} + const { importMap } = props.payload + const { user } = props + const { req } = props.initPageResult + const { i18n } = req + + const layout = + (await getItemsFromPreferences(props.payload, user)) ?? + (await getItemsFromConfig(defaultLayout, req, widgets)) + + const serverLayout: ServerLayout = layout.map((layoutItem) => { + const widgetSlug = layoutItem.id.slice(0, layoutItem.id.lastIndexOf('-')) + return { + component: RenderServerComponent({ + Component: widgets.find((widget) => widget.slug === widgetSlug)?.ComponentPath, + importMap, + serverProps: { + req, + widgetSlug, + // TODO: widgets will support state in the future + // widgetData: layoutItem.data, + } satisfies WidgetServerProps, + }), + item: layoutItem, + } + }) + + // Resolve function labels to static labels for client components + const clientWidgets: ClientWidget[] = widgets.map((widget) => { + const { ComponentPath: _, label, ...rest } = widget + return { + ...rest, + label: typeof label === 'function' ? label({ i18n, t: i18n.t as TFunction }) : label, + } + }) + + return ( +
+ +
+ ) +} + +async function getItemsFromPreferences( + payload: BasePayload, + user: TypedUser, +): Promise { + const savedPreferences = await getPreferences( + 'dashboard-layout', + payload, + user.id, + user.collection, + ) + if ( + !savedPreferences?.value || + typeof savedPreferences.value !== 'object' || + !('layouts' in savedPreferences.value) + ) { + return null + } + return savedPreferences.value.layouts as null | WidgetItem[] +} + +async function getItemsFromConfig( + defaultLayout: NonNullable, + req: PayloadRequest, + widgets: Widget[], +): Promise { + // Handle function format + let widgetInstances: WidgetInstance[] + if (typeof defaultLayout === 'function') { + widgetInstances = await defaultLayout({ req }) + } else { + widgetInstances = defaultLayout + } + + return widgetInstances.map((widgetInstance, index) => { + const widget = widgets.find((widget) => widget.slug === widgetInstance.widgetSlug) + return { + id: `${widgetInstance.widgetSlug}-${index}`, + maxWidth: widget?.maxWidth ?? 'full', + minWidth: widget?.minWidth ?? 'x-small', + width: widgetInstance.width || 'x-small', + } + }) +} diff --git a/packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/RenderWidget.tsx b/packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/RenderWidget.tsx new file mode 100644 index 00000000000..baea1a6d121 --- /dev/null +++ b/packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/RenderWidget.tsx @@ -0,0 +1,82 @@ +'use client' + +import { ShimmerEffect, useServerFunctions } from '@payloadcms/ui' +import React, { useCallback, useEffect, useRef } from 'react' + +import type { + RenderWidgetServerFnArgs, + RenderWidgetServerFnReturnType, +} from './renderWidgetServerFn.js' + +/** + * Utility to render a widget on-demand on the client. + */ +export const RenderWidget: React.FC<{ + /** + * Instance-specific data for this widget + */ + // TODO: widgetData?: Record + /** + * Unique ID for this widget instance (format: "slug-timestamp") + */ + widgetId: string +}> = ({ /* widgetData, */ widgetId }) => { + const [Component, setComponent] = React.useState(null) + const { serverFunction } = useServerFunctions() + + const renderWidget = useCallback(() => { + async function render() { + try { + const widgetSlug = widgetId.slice(0, widgetId.lastIndexOf('-')) + + const result = (await serverFunction({ + name: 'render-widget', + args: { + // TODO: widgets will support state in the future + // widgetData, + widgetSlug, + } as RenderWidgetServerFnArgs, + })) as RenderWidgetServerFnReturnType + + setComponent(result.component) + } catch (error) { + // Log error but don't expose details to console in production + + // Fallback error component + setComponent( + React.createElement( + 'div', + { + style: { + background: 'var(--theme-error-50)', + border: '1px solid var(--theme-error-200)', + borderRadius: '4px', + color: 'var(--theme-error-text)', + padding: '20px', + textAlign: 'center', + }, + }, + 'Failed to load widget. Please try again later.', + ), + ) + } + } + void render() + }, [serverFunction, widgetId /* widgetData, */]) + + const mounted = useRef(false) + + useEffect(() => { + if (mounted.current) { + return + } + mounted.current = true + void renderWidget() + }, [renderWidget]) + + if (!Component) { + return + } + + return <>{Component} +} diff --git a/packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.ts b/packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.ts new file mode 100644 index 00000000000..441e910f1ff --- /dev/null +++ b/packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/getDefaultLayoutServerFn.ts @@ -0,0 +1,76 @@ +import type { + DashboardConfig, + PayloadRequest, + ServerFunction, + Widget, + WidgetServerProps, +} from 'payload' + +import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' + +import type { WidgetInstanceClient, WidgetItem } from '../index.client.js' + +export type GetDefaultLayoutServerFnArgs = Record + +export type GetDefaultLayoutServerFnReturnType = { + layout: WidgetInstanceClient[] +} + +/** + * Server function to get the default dashboard layout on-demand. + * Used when resetting the dashboard to its default configuration. + */ +export const getDefaultLayoutHandler: ServerFunction< + GetDefaultLayoutServerFnArgs, + Promise +> = async ({ req }) => { + if (!req.user) { + throw new Error('Unauthorized') + } + + const { defaultLayout = [], widgets = [] } = req.payload.config.admin.dashboard || {} + const { importMap } = req.payload + + const layoutItems = await getItemsFromConfig(defaultLayout, req, widgets) + + const layout: WidgetInstanceClient[] = layoutItems.map((layoutItem) => { + const widgetSlug = layoutItem.id.slice(0, layoutItem.id.lastIndexOf('-')) + return { + component: RenderServerComponent({ + Component: widgets.find((widget) => widget.slug === widgetSlug)?.ComponentPath, + importMap, + serverProps: { + req, + widgetSlug, + } satisfies WidgetServerProps, + }), + item: layoutItem, + } + }) + + return { layout } +} + +async function getItemsFromConfig( + defaultLayout: NonNullable, + req: PayloadRequest, + widgets: Widget[], +): Promise { + // Handle function format + let widgetInstances + if (typeof defaultLayout === 'function') { + widgetInstances = await defaultLayout({ req }) + } else { + widgetInstances = defaultLayout + } + + return widgetInstances.map((widgetInstance, index) => { + const widget = widgets.find((w) => w.slug === widgetInstance.widgetSlug) + return { + id: `${widgetInstance.widgetSlug}-${index}`, + maxWidth: widget?.maxWidth ?? 'full', + minWidth: widget?.minWidth ?? 'x-small', + width: widgetInstance.width || 'x-small', + } + }) +} diff --git a/packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.ts b/packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.ts new file mode 100644 index 00000000000..b8970f60ade --- /dev/null +++ b/packages/next/src/views/Dashboard/Default/ModularDashboard/renderWidget/renderWidgetServerFn.ts @@ -0,0 +1,100 @@ +import type { ServerFunction, WidgetServerProps } from 'payload' + +import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' +import React from 'react' + +export type RenderWidgetServerFnArgs = { + /** + * Instance-specific data for this widget + */ + // TODO: widgets will support state in the future + // widgetData?: Record + /** + * The slug of the widget to render + */ + widgetSlug: string +} + +export type RenderWidgetServerFnReturnType = { + component: React.ReactNode +} + +/** + * Server function to render a widget on-demand. + * Similar to render-field but specifically for dashboard widgets. + */ +export const renderWidgetHandler: ServerFunction< + RenderWidgetServerFnArgs, + RenderWidgetServerFnReturnType +> = ({ req, /* widgetData, */ widgetSlug }) => { + if (!req.user) { + throw new Error('Unauthorized') + } + + const { widgets } = req.payload.config.admin.dashboard + const { importMap } = req.payload + + // Find the widget configuration + const widgetConfig = widgets.find((widget) => widget.slug === widgetSlug) + + if (!widgetConfig) { + return { + component: React.createElement( + 'div', + { + style: { + background: 'var(--theme-elevation-50)', + border: '1px solid var(--theme-elevation-200)', + borderRadius: '4px', + color: 'var(--theme-text)', + padding: '20px', + textAlign: 'center', + }, + }, + `Widget "${widgetSlug}" not found`, + ), + } + } + + try { + // Create server props for the widget + const serverProps: WidgetServerProps = { + req, + // TODO: widgetData: widgetData || {}, + widgetSlug, + } + + // Render the widget server component + const component = RenderServerComponent({ + Component: widgetConfig.ComponentPath, + importMap, + serverProps, + }) + + return { component } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error) + + req.payload.logger.error({ + err: error, + msg: `Error rendering widget "${widgetSlug}": ${errorMessage}`, + }) + + return { + component: React.createElement( + 'div', + { + style: { + background: 'var(--theme-error-50)', + border: '1px solid var(--theme-error-200)', + borderRadius: '4px', + color: 'var(--theme-error-text)', + padding: '20px', + textAlign: 'center', + }, + }, + 'Error loading widget', + ), + } + } +} diff --git a/packages/next/src/views/Dashboard/Default/ModularDashboard/useDashboardLayout.ts b/packages/next/src/views/Dashboard/Default/ModularDashboard/useDashboardLayout.ts new file mode 100644 index 00000000000..a193b2a40bd --- /dev/null +++ b/packages/next/src/views/Dashboard/Default/ModularDashboard/useDashboardLayout.ts @@ -0,0 +1,206 @@ +import type { WidgetWidth } from 'payload' + +import { arrayMove } from '@dnd-kit/sortable' +import { + ConfirmationModal, + toast, + useConfig, + useModal, + usePreferences, + useServerFunctions, +} from '@payloadcms/ui' +import React, { useCallback, useState } from 'react' + +import type { WidgetInstanceClient, WidgetItem } from './index.client.js' +import type { GetDefaultLayoutServerFnReturnType } from './renderWidget/getDefaultLayoutServerFn.js' + +import { RenderWidget } from './renderWidget/RenderWidget.js' + +export function useDashboardLayout(initialLayout: WidgetInstanceClient[]) { + const setLayoutPreference = useSetLayoutPreference() + const [isEditing, setIsEditing] = useState(false) + const { widgets = [] } = useConfig().config.admin.dashboard ?? {} + const [currentLayout, setCurrentLayout] = useState(initialLayout) + const { openModal } = useModal() + const cancelModalSlug = 'cancel-dashboard-changes' + const { serverFunction } = useServerFunctions() + + const saveLayout = useCallback(async () => { + try { + const layoutData: WidgetItem[] = currentLayout.map((item) => item.item) + setIsEditing(false) + await setLayoutPreference(layoutData) + } catch { + setIsEditing(true) + toast.error('Failed to save layout') + } + }, [setLayoutPreference, currentLayout]) + + const resetLayout = useCallback(async () => { + try { + await setLayoutPreference(null) + + const result = (await serverFunction({ + name: 'get-default-layout', + args: {}, + })) as GetDefaultLayoutServerFnReturnType + + setCurrentLayout(result.layout) + setIsEditing(false) + } catch { + toast.error('Failed to reset layout') + } + }, [setLayoutPreference, serverFunction]) + + const performCancel = useCallback(() => { + setCurrentLayout(initialLayout) + setIsEditing(false) + }, [initialLayout]) + + const cancel = useCallback(() => { + // Check if layout has changed + const hasChanges = + currentLayout.length !== initialLayout.length || + currentLayout.some((widget, index) => { + const initialWidget = initialLayout[index] + return ( + !initialWidget || + widget.item.id !== initialWidget.item.id || + widget.item.width !== initialWidget.item.width + ) + }) + + // If there are changes, show confirmation modal + if (hasChanges) { + openModal(cancelModalSlug) + } else { + performCancel() + } + }, [currentLayout, initialLayout, openModal, cancelModalSlug, performCancel]) + + const moveWidget = useCallback( + ({ moveFromIndex, moveToIndex }: { moveFromIndex: number; moveToIndex: number }) => { + if (moveFromIndex === moveToIndex || moveFromIndex < 0 || moveToIndex < 0) { + return + } + + setCurrentLayout((prev) => { + return arrayMove(prev, moveFromIndex, moveToIndex) + }) + }, + [], + ) + + const addWidget = useCallback( + (widgetSlug: string) => { + if (!isEditing) { + return + } + + const widgetId = `${widgetSlug}-${Date.now()}` + const widget = widgets.find((widget) => widget.slug === widgetSlug) + + // Create a new widget instance using RenderWidget + const newWidgetInstance: WidgetInstanceClient = { + component: React.createElement(RenderWidget, { + widgetId, + // TODO: widgetData can be added here for custom props + }), + item: { + id: widgetId, + maxWidth: widget?.maxWidth ?? 'full', + minWidth: widget?.minWidth ?? 'x-small', + width: widget?.minWidth ?? 'x-small', + }, + } + + setCurrentLayout((prev) => [...prev, newWidgetInstance]) + + // Scroll to the newly added widget after it's rendered and highlight it + setTimeout(() => { + const element = document.getElementById(widgetId) + if (element) { + element.scrollIntoView({ + behavior: 'smooth', + block: 'center', + }) + + // Add highlight animation to the widget element + const widget = element.closest('.widget') + if (widget) { + widget.classList.add('widget--highlight') + // Remove the class after animation completes (1.5s fade out) + setTimeout(() => { + widget.classList.remove('widget--highlight') + }, 1500) + } + } + }, 100) + }, + [isEditing, widgets], + ) + + const deleteWidget = useCallback( + (widgetId: string) => { + if (!isEditing) { + return + } + setCurrentLayout((prev) => prev.filter((item) => item.item.id !== widgetId)) + }, + [isEditing], + ) + + const resizeWidget = useCallback( + (widgetId: string, newWidth: WidgetWidth) => { + if (!isEditing) { + return + } + setCurrentLayout((prev) => + prev.map((item) => + item.item.id === widgetId + ? { + ...item, + item: { + ...item.item, + width: newWidth, + } satisfies WidgetItem, + } + : item, + ), + ) + }, + [isEditing], + ) + + const cancelModal = React.createElement(ConfirmationModal, { + body: 'You have unsaved changes to your dashboard layout. Are you sure you want to discard them?', + confirmLabel: 'Discard', + heading: 'Discard changes?', + modalSlug: cancelModalSlug, + onConfirm: performCancel, + }) + + return { + addWidget, + cancel, + cancelModal, + currentLayout, + deleteWidget, + isEditing, + moveWidget, + resetLayout, + resizeWidget, + saveLayout, + setIsEditing, + } +} + +function useSetLayoutPreference() { + const { setPreference } = usePreferences() + return useCallback( + async (layout: null | WidgetItem[]) => { + await setPreference('dashboard-layout', { layouts: layout }, false) + }, + [setPreference], + ) +} diff --git a/packages/next/src/views/Dashboard/Default/ModularDashboard/utils/collisionDetection.ts b/packages/next/src/views/Dashboard/Default/ModularDashboard/utils/collisionDetection.ts new file mode 100644 index 00000000000..8b140b2b112 --- /dev/null +++ b/packages/next/src/views/Dashboard/Default/ModularDashboard/utils/collisionDetection.ts @@ -0,0 +1,40 @@ +import type { CollisionDetection } from '@dnd-kit/core' + +/** + * Collision detection that considers the X + * axis only with respect to the position of the pointer (or collisionRect for keyboard) + */ +export const closestInXAxis: CollisionDetection = (args) => { + const collisions: Array<{ data: { value: number }; id: string }> = [] + + // Use pointer coordinates if available (mouse/touch), otherwise use collisionRect center (keyboard) + let x: number + let y: number + + if (args.pointerCoordinates) { + x = args.pointerCoordinates.x + y = args.pointerCoordinates.y + } else if (args.collisionRect) { + // For keyboard navigation, use the center of the collisionRect + x = args.collisionRect.left + args.collisionRect.width / 2 + y = args.collisionRect.top + args.collisionRect.height / 2 + } else { + return [] + } + + for (const container of args.droppableContainers) { + const rect = args.droppableRects.get(container.id) + if (!rect) { + continue + } + + // Only consider widgets in the same row (same Y axis) + if (y >= rect.top && y <= rect.bottom) { + const centerX = rect.left + rect.width / 2 + const distance = Math.abs(x - centerX) + collisions.push({ id: String(container.id), data: { value: distance } }) + } + } + + return collisions.sort((a, b) => a.data.value - b.data.value) +} diff --git a/packages/next/src/views/Dashboard/Default/ModularDashboard/utils/sensors.ts b/packages/next/src/views/Dashboard/Default/ModularDashboard/utils/sensors.ts new file mode 100644 index 00000000000..3c9c5d0cfa6 --- /dev/null +++ b/packages/next/src/views/Dashboard/Default/ModularDashboard/utils/sensors.ts @@ -0,0 +1,319 @@ +import type { KeyboardCoordinateGetter, KeyboardSensorOptions } from '@dnd-kit/core' + +import { KeyboardCode, KeyboardSensor, PointerSensor, useSensor, useSensors } from '@dnd-kit/core' + +type DroppablePosition = { + centerX: number + centerY: number + element: Element + isBeforeDroppable: boolean + rect: DOMRect + row: number +} + +/** + * Get all droppable widget positions, filtering out overlapping "before" droppables + * and assigning row numbers based on Y position. + */ +function getDroppablePositions(): DroppablePosition[] { + const positionTolerance = 5 + const rowTolerance = 10 + const result: DroppablePosition[] = [] + let currentRow = 0 + let currentY: null | number = null + + const allDroppables = Array.from(document.querySelectorAll('.droppable-widget')) + + for (let i = 0; i < allDroppables.length; i++) { + const element = allDroppables[i] + const rect = element.getBoundingClientRect() + + // Skip hidden elements + if (rect.width === 0 || rect.height === 0) { + continue + } + + const centerX = rect.left + rect.width / 2 + const centerY = rect.top + rect.height / 2 + const testId = element.getAttribute('data-testid') || '' + const isBeforeDroppable = testId.endsWith('-before') + + // Skip "before" droppables that overlap with another droppable + if (isBeforeDroppable) { + const hasOverlapping = allDroppables.some((other, otherIndex) => { + if (otherIndex === i) { + return false + } + const otherRect = other.getBoundingClientRect() + const otherCenterX = otherRect.left + otherRect.width / 2 + const otherCenterY = otherRect.top + otherRect.height / 2 + return ( + Math.abs(otherCenterX - centerX) < positionTolerance && + Math.abs(otherCenterY - centerY) < positionTolerance + ) + }) + if (hasOverlapping) { + continue + } + } + + // Assign row number based on Y position change + if (currentY === null) { + currentY = centerY + } else if (Math.abs(centerY - currentY) >= rowTolerance) { + currentRow++ + currentY = centerY + } + + result.push({ + centerX, + centerY, + element, + isBeforeDroppable, + rect, + row: currentRow, + }) + } + + return result +} + +/** + * Find the row with the closest Y position to the given posY. + * Returns the row index, or null if no droppables exist. + */ +function findClosestRow(droppables: DroppablePosition[], posY: number): null | number { + if (droppables.length === 0) { + return null + } + + let closestRow = droppables[0].row + let minYDistance = Infinity + + for (const droppable of droppables) { + const yDistance = Math.abs(droppable.centerY - posY) + if (yDistance < minYDistance) { + minYDistance = yDistance + closestRow = droppable.row + } + } + + return closestRow +} + +/** + * Find the closest droppable within a specific row by X position. + * Returns the droppable and its index, or null if no droppables in that row. + */ +function findClosestDroppableInRow( + droppables: DroppablePosition[], + rowIndex: number, + posX: number, +): { droppable: DroppablePosition; index: number } | null { + let closestIndex = -1 + let minXDistance = Infinity + + for (let i = 0; i < droppables.length; i++) { + const droppable = droppables[i] + if (droppable.row === rowIndex) { + const xDistance = Math.abs(droppable.centerX - posX) + if (xDistance < minXDistance) { + minXDistance = xDistance + closestIndex = i + } + } + } + + if (closestIndex === -1) { + return null + } + + return { droppable: droppables[closestIndex], index: closestIndex } +} + +/** + * Find the target droppable based on direction + * - ArrowRight/Left: Next/previous in DOM order (now that overlapping droppables are filtered) + * - ArrowUp/Down: Closest in adjacent row (row +1 or -1) by X position + */ +function findTargetDroppable( + droppables: DroppablePosition[], + currentCenterX: number, + currentCenterY: number, + direction: string, +): DroppablePosition | null { + // Find the closest row, then the closest droppable in that row + const currentRow = findClosestRow(droppables, currentCenterY) + + if (currentRow === null) { + return null + } + + const currentDroppable = findClosestDroppableInRow(droppables, currentRow, currentCenterX) + + if (!currentDroppable) { + return null + } + + const { index: currentIndex } = currentDroppable + + switch (direction) { + case 'ArrowDown': { + const targetRow = currentRow + 1 + return findClosestDroppableInRow(droppables, targetRow, currentCenterX)?.droppable || null + } + + case 'ArrowLeft': + // Previous in DOM order + return droppables[currentIndex - 1] || null + + case 'ArrowRight': + // Next in DOM order + return droppables[currentIndex + 1] || null + + case 'ArrowUp': { + const targetRow = currentRow - 1 + return findClosestDroppableInRow(droppables, targetRow, currentCenterX)?.droppable || null + } + + default: + return null + } +} + +/** + * Custom coordinate getter that jumps directly to droppable positions + * instead of moving in pixel increments. This works better with scrolling + * and provides more predictable navigation. + */ +const droppableJumpKeyboardCoordinateGetter: KeyboardCoordinateGetter = ( + event, + { context, currentCoordinates }, +) => { + const { collisionRect } = context + const { code } = event + + if (!collisionRect) { + return currentCoordinates + } + + // Only handle arrow keys + if (!['ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowUp'].includes(code)) { + return currentCoordinates + } + + // Prevent default browser scroll behavior for arrow keys + event.preventDefault() + + // Clear scrollableAncestors to prevent dnd-kit from scrolling instead of moving + // This must be done on every keydown because context is updated by dnd-kit + if (context.scrollableAncestors) { + context.scrollableAncestors.length = 0 + } + + // Get all droppable widgets and their positions + const droppables = getDroppablePositions() + + if (droppables.length === 0) { + return currentCoordinates + } + + // Current position center (viewport coordinates from collisionRect) + const currentCenterX = collisionRect.left + collisionRect.width / 2 + const currentCenterY = collisionRect.top + collisionRect.height / 2 + + // Find the target droppable based on direction + const targetDroppable = findTargetDroppable(droppables, currentCenterX, currentCenterY, code) + + // If we found a target, scroll if needed and calculate the delta + if (targetDroppable) { + const viewportHeight = window.innerHeight + const targetRect = targetDroppable.rect + const scrollPadding = 20 // Extra padding to ensure element is fully visible + + // Check if target droppable is fully visible in viewport + const isAboveViewport = targetRect.top < scrollPadding + const isBelowViewport = targetRect.bottom > viewportHeight - scrollPadding + + // Scroll to make target visible (using instant scroll for synchronous behavior) + if (isAboveViewport) { + const scrollAmount = targetRect.top - scrollPadding + // don't use smooth scroll here, because it will mess up the delta calculation + window.scrollBy({ behavior: 'instant', top: scrollAmount }) + } else if (isBelowViewport) { + const scrollAmount = targetRect.bottom - viewportHeight + scrollPadding + window.scrollBy({ behavior: 'instant', top: scrollAmount }) + } + + // After scroll, recalculate target position (it may have changed due to scroll) + const newTargetRect = targetDroppable.element.getBoundingClientRect() + const newTargetCenterX = newTargetRect.left + newTargetRect.width / 2 + const newTargetCenterY = newTargetRect.top + newTargetRect.height / 2 + + // Calculate delta using current overlay position (which didn't change) and new target position + const deltaX = newTargetCenterX - currentCenterX + const deltaY = newTargetCenterY - currentCenterY + + // Add delta to currentCoordinates to position overlay's center at target's center + return { + x: currentCoordinates.x + deltaX, + y: currentCoordinates.y + deltaY, + } + } + + // No valid target found, stay in place + return currentCoordinates +} + +/** + * Custom KeyboardSensor that only activates when focus is directly on the + * draggable element, not on any of its descendants. This allows interactive + * elements inside draggables (like buttons) to work normally with the keyboard. + */ +class DirectFocusKeyboardSensor extends KeyboardSensor { + static override activators = [ + { + eventName: 'onKeyDown' as const, + handler: ( + event: React.KeyboardEvent, + { + keyboardCodes = { + cancel: [KeyboardCode.Esc], + end: [KeyboardCode.Space, KeyboardCode.Enter], + start: [KeyboardCode.Space, KeyboardCode.Enter], + }, + onActivation, + }: KeyboardSensorOptions, + { active }: { active: { node: React.MutableRefObject } }, + ) => { + const { code } = event.nativeEvent + + // Only activate if focus is directly on the draggable node, not descendants + if (event.target !== active.node.current) { + return false + } + + if (keyboardCodes.start.includes(code)) { + event.preventDefault() + onActivation?.({ event: event.nativeEvent }) + return true + } + + return false + }, + }, + ] +} + +export function useDashboardSensors() { + return useSensors( + useSensor(PointerSensor, { + activationConstraint: { + distance: 5, + }, + }), + useSensor(DirectFocusKeyboardSensor, { + coordinateGetter: droppableJumpKeyboardCoordinateGetter, + }), + ) +} diff --git a/packages/next/src/views/Dashboard/Default/index.tsx b/packages/next/src/views/Dashboard/Default/index.tsx index 14e129d7b91..6e996dabf84 100644 --- a/packages/next/src/views/Dashboard/Default/index.tsx +++ b/packages/next/src/views/Dashboard/Default/index.tsx @@ -1,14 +1,11 @@ import type { groupNavItems } from '@payloadcms/ui/shared' import type { AdminViewServerPropsOnly, ClientUser, Locale, ServerProps } from 'payload' -import { getTranslation } from '@payloadcms/translations' -import { Button, Card, Gutter, Locked } from '@payloadcms/ui' +import { Gutter } from '@payloadcms/ui' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' -import { EntityType } from '@payloadcms/ui/shared' -import { formatAdminURL } from 'payload/shared' -import React, { Fragment } from 'react' +import React from 'react' -import './index.scss' +import { ModularDashboard } from './ModularDashboard/index.js' const baseClass = 'dashboard' @@ -16,6 +13,15 @@ export type DashboardViewClientProps = { locale: Locale } +// Neither DashboardViewClientProps, DashboardViewServerPropsOnly, nor +// DashboardViewServerProps make much sense. They were created +// before the modular dashboard existed, and they are tightly coupled to +// the default layout of collection and global cards. All of their values +// could have been derived from the req object, and the same likely applies +// to other views. These types remain only for backward compatibility. +// It is recommended to use the modular dashboard widgets, which have props +// that are more agnostic to their content. + export type DashboardViewServerPropsOnly = { globalData: Array<{ data: { _isLocked: boolean; _lastEditedAt: string; _userEditing: ClientUser | number | string } @@ -34,169 +40,40 @@ export type DashboardViewServerPropsOnly = { export type DashboardViewServerProps = DashboardViewClientProps & DashboardViewServerPropsOnly export function DefaultDashboard(props: DashboardViewServerProps) { - const { - globalData, - i18n, - i18n: { t }, - locale, - navGroups, - params, - payload: { - config: { - admin: { - components: { afterDashboard, beforeDashboard }, - }, - routes: { admin: adminRoute }, - serverURL, - }, - }, - payload, - permissions, - searchParams, - user, - } = props + const { i18n, locale, params, payload, permissions, searchParams, user } = props + const { afterDashboard, beforeDashboard } = payload.config.admin.components return ( -
- - {beforeDashboard && - RenderServerComponent({ - Component: beforeDashboard, - importMap: payload.importMap, - serverProps: { - i18n, - locale, - params, - payload, - permissions, - searchParams, - user, - } satisfies ServerProps, - })} - - - {!navGroups || navGroups?.length === 0 ? ( -

no nav groups....

- ) : ( - navGroups.map(({ entities, label }, groupIndex) => { - return ( -
-

{label}

-
    - {entities.map(({ slug, type, label }, entityIndex) => { - let title: string - let buttonAriaLabel: string - let createHREF: string - let href: string - let hasCreatePermission: boolean - let isLocked = null - let userEditing = null - - if (type === EntityType.collection) { - title = getTranslation(label, i18n) - - buttonAriaLabel = t('general:showAllLabel', { label: title }) - - href = formatAdminURL({ - adminRoute, - path: `/collections/${slug}`, - serverURL, - }) - - createHREF = formatAdminURL({ - adminRoute, - path: `/collections/${slug}/create`, - serverURL, - }) - - hasCreatePermission = permissions?.collections?.[slug]?.create - } - - if (type === EntityType.global) { - title = getTranslation(label, i18n) - - buttonAriaLabel = t('general:editLabel', { - label: getTranslation(label, i18n), - }) - - href = formatAdminURL({ - adminRoute, - path: `/globals/${slug}`, - serverURL, - }) - - // Find the lock status for the global - const globalLockData = globalData.find((global) => global.slug === slug) - if (globalLockData) { - isLocked = globalLockData.data._isLocked - userEditing = globalLockData.data._userEditing - - // Check if the lock is expired - const lockDuration = globalLockData?.lockDuration - const lastEditedAt = new Date( - globalLockData.data?._lastEditedAt, - ).getTime() - - const lockDurationInMilliseconds = lockDuration * 1000 - const lockExpirationTime = lastEditedAt + lockDurationInMilliseconds - - if (new Date().getTime() > lockExpirationTime) { - isLocked = false - userEditing = null - } - } - } - - return ( -
  • - - ) : hasCreatePermission && type === EntityType.collection ? ( -
  • - ) - })} -
-
- ) - }) - )} -
- {afterDashboard && - RenderServerComponent({ - Component: afterDashboard, - importMap: payload.importMap, - serverProps: { - i18n, - locale, - params, - payload, - permissions, - searchParams, - user, - } satisfies ServerProps, - })} -
-
+ + {beforeDashboard && + RenderServerComponent({ + Component: beforeDashboard, + importMap: payload.importMap, + serverProps: { + i18n, + locale, + params, + payload, + permissions, + searchParams, + user, + } satisfies ServerProps, + })} + + {afterDashboard && + RenderServerComponent({ + Component: afterDashboard, + importMap: payload.importMap, + serverProps: { + i18n, + locale, + params, + payload, + permissions, + searchParams, + user, + } satisfies ServerProps, + })} + ) } diff --git a/packages/next/src/views/Dashboard/index.tsx b/packages/next/src/views/Dashboard/index.tsx index 77d2667c483..576ae264656 100644 --- a/packages/next/src/views/Dashboard/index.tsx +++ b/packages/next/src/views/Dashboard/index.tsx @@ -1,17 +1,14 @@ -import type { EntityToGroup } from '@payloadcms/ui/shared' -import type { AdminViewServerProps, TypedUser } from 'payload' +import type { AdminViewServerProps } from 'payload' import { HydrateAuthProvider, SetStepNav } from '@payloadcms/ui' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' -import { EntityType, groupNavItems } from '@payloadcms/ui/shared' +import { getGlobalData, getNavGroups } from '@payloadcms/ui/shared' import React, { Fragment } from 'react' import type { DashboardViewClientProps, DashboardViewServerPropsOnly } from './Default/index.js' import { DefaultDashboard } from './Default/index.js' -const globalLockDurationDefault = 300 - export async function DashboardView(props: AdminViewServerProps) { const { locale, @@ -25,82 +22,9 @@ export async function DashboardView(props: AdminViewServerProps) { req, visibleEntities, } = props.initPageResult - const collections = config.collections.filter( - (collection) => - permissions?.collections?.[collection.slug]?.read && - visibleEntities.collections.includes(collection.slug), - ) - - const globals = config.globals.filter( - (global) => - permissions?.globals?.[global.slug]?.read && visibleEntities.globals.includes(global.slug), - ) - - // Query locked global documents only if there are globals in the config - let globalData: DashboardViewServerPropsOnly['globalData'] = [] - - if (config.globals.length > 0) { - const lockedDocuments = await payload.find({ - collection: 'payload-locked-documents', - depth: 1, - overrideAccess: false, - pagination: false, - req, - select: { - globalSlug: true, - updatedAt: true, - user: true, - }, - where: { - globalSlug: { - exists: true, - }, - }, - }) - - // Map over globals to include `lockDuration` and lock data for each global slug - globalData = config.globals.map((global) => { - const lockDuration = - typeof global.lockDocuments === 'object' - ? global.lockDocuments.duration - : globalLockDurationDefault - const lockedDoc = lockedDocuments.docs.find((doc) => doc.globalSlug === global.slug) - - return { - slug: global.slug, - data: { - _isLocked: !!lockedDoc, - _lastEditedAt: (lockedDoc?.updatedAt as string) ?? null, - _userEditing: (lockedDoc?.user as { value?: TypedUser })?.value ?? null, - }, - lockDuration, - } - }) - } - - const navGroups = groupNavItems( - [ - ...(collections.map((collection) => { - const entityToGroup: EntityToGroup = { - type: EntityType.collection, - entity: collection, - } - - return entityToGroup - }) ?? []), - ...(globals.map((global) => { - const entityToGroup: EntityToGroup = { - type: EntityType.global, - entity: global, - } - - return entityToGroup - }) ?? []), - ], - permissions, - i18n, - ) + const globalData = await getGlobalData(req) + const navGroups = getNavGroups(permissions, visibleEntities, config, i18n) return ( diff --git a/packages/next/src/views/NotFound/index.tsx b/packages/next/src/views/NotFound/index.tsx index 72d3e9aaa5a..f58d78f44e8 100644 --- a/packages/next/src/views/NotFound/index.tsx +++ b/packages/next/src/views/NotFound/index.tsx @@ -1,13 +1,13 @@ import type { Metadata } from 'next' import type { AdminViewServerProps, ImportMap, SanitizedConfig } from 'payload' +import { getVisibleEntities } from '@payloadcms/ui/shared' import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React from 'react' import { DefaultTemplate } from '../../templates/Default/index.js' import { getNextRequestI18n } from '../../utilities/getNextRequestI18n.js' -import { getVisibleEntities } from '../../utilities/getVisibleEntities.js' import { initReq } from '../../utilities/initReq.js' import { NotFoundClient } from './index.client.js' diff --git a/packages/next/src/views/Root/index.tsx b/packages/next/src/views/Root/index.tsx index e43278a4f86..d56b5282d57 100644 --- a/packages/next/src/views/Root/index.tsx +++ b/packages/next/src/views/Root/index.tsx @@ -12,6 +12,7 @@ import type { import { PageConfigProvider } from '@payloadcms/ui' import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' +import { getVisibleEntities } from '@payloadcms/ui/shared' import { getClientConfig } from '@payloadcms/ui/utilities/getClientConfig' import { notFound, redirect } from 'next/navigation.js' import { applyLocaleFiltering, formatAdminURL } from 'payload/shared' @@ -21,7 +22,6 @@ import React from 'react' import { DefaultTemplate } from '../../templates/Default/index.js' import { MinimalTemplate } from '../../templates/Minimal/index.js' import { getPreferences } from '../../utilities/getPreferences.js' -import { getVisibleEntities } from '../../utilities/getVisibleEntities.js' import { handleAuthRedirect } from '../../utilities/handleAuthRedirect.js' import { initReq } from '../../utilities/initReq.js' import { isCustomAdminView } from '../../utilities/isCustomAdminView.js' diff --git a/packages/payload/src/admin/types.ts b/packages/payload/src/admin/types.ts index 265ff233279..082b45e083a 100644 --- a/packages/payload/src/admin/types.ts +++ b/packages/payload/src/admin/types.ts @@ -590,6 +590,8 @@ export type { LanguageOptions } from './LanguageOptions.js' export type { RichTextAdapter, RichTextAdapterProvider, RichTextHooks } from './RichText.js' +export { type WidgetServerProps } from './views/dashboard.js' + export type { BeforeDocumentControlsClientProps, BeforeDocumentControlsServerProps, diff --git a/packages/payload/src/admin/views/dashboard.ts b/packages/payload/src/admin/views/dashboard.ts new file mode 100644 index 00000000000..65e6d40067f --- /dev/null +++ b/packages/payload/src/admin/views/dashboard.ts @@ -0,0 +1,12 @@ +import type { PayloadRequest } from '../../index.js' + +export enum EntityType { + collection = 'collections', + global = 'globals', +} + +export type WidgetServerProps = { + req: PayloadRequest + widgetData?: Record + widgetSlug: string +} diff --git a/packages/payload/src/bin/generateImportMap/iterateConfig.ts b/packages/payload/src/bin/generateImportMap/iterateConfig.ts index 50163790baf..54f4c245b7d 100644 --- a/packages/payload/src/bin/generateImportMap/iterateConfig.ts +++ b/packages/payload/src/bin/generateImportMap/iterateConfig.ts @@ -80,6 +80,12 @@ export function iterateConfig({ } } + if (config.admin?.dashboard?.widgets?.length) { + for (const dashboardWidget of config.admin.dashboard.widgets) { + addToImportMap(dashboardWidget.ComponentPath) + } + } + if (config?.admin?.importMap?.generators?.length) { for (const generator of config.admin.importMap.generators) { generator({ diff --git a/packages/payload/src/config/client.ts b/packages/payload/src/config/client.ts index 6f09d5a3a76..f05a902de41 100644 --- a/packages/payload/src/config/client.ts +++ b/packages/payload/src/config/client.ts @@ -1,4 +1,4 @@ -import type { I18nClient } from '@payloadcms/translations' +import type { I18nClient, TFunction } from '@payloadcms/translations' import type { DeepPartial } from 'ts-essentials' import type { ImportMap } from '../bin/generateImportMap/index.js' @@ -7,6 +7,7 @@ import type { BlockSlug, TypedUser } from '../index.js' import type { RootLivePreviewConfig, SanitizedConfig, + SanitizedDashboardConfig, ServerOnlyLivePreviewProperties, } from './types.js' @@ -45,8 +46,9 @@ export type ServerOnlyRootAdminProperties = keyof Pick - } & Omit + } & Omit blocks: ClientBlock[] blocksMap: Record collections: ClientCollectionConfig[] @@ -176,6 +178,20 @@ export const createClientConfig = ({ user: config.admin.user, } + if (config.admin.dashboard?.widgets) { + ;(clientConfig.admin.dashboard ??= {}).widgets = config.admin.dashboard.widgets.map( + (widget) => { + const { ComponentPath: _, label, ...rest } = widget + return { + ...rest, + // Resolve label function to string for client + label: + typeof label === 'function' ? label({ i18n, t: i18n.t as TFunction }) : label, + } + }, + ) + } + if (config.admin.livePreview) { clientConfig.admin.livePreview = {} diff --git a/packages/payload/src/config/sanitize.ts b/packages/payload/src/config/sanitize.ts index dd0afcc1916..bedf2281a82 100644 --- a/packages/payload/src/config/sanitize.ts +++ b/packages/payload/src/config/sanitize.ts @@ -1,4 +1,4 @@ -import type { AcceptedLanguages, Language } from '@payloadcms/translations' +import type { AcceptedLanguages } from '@payloadcms/translations' import { en } from '@payloadcms/translations/languages/en' import { deepMergeSimple } from '@payloadcms/translations/utilities' @@ -11,6 +11,7 @@ import type { LocalizationConfigWithNoLabels, SanitizedConfig, Timezone, + WidgetInstance, } from './types.js' import { defaultUserCollection } from '../auth/defaultUser.js' @@ -53,6 +54,17 @@ const sanitizeAdminConfig = (configToSanitize: Config): Partial ValidationError: 'info', ...(sanitizedConfig.loggingLevels || {}), } + ;(sanitizedConfig.admin!.dashboard ??= { widgets: [] }).widgets.push({ + slug: 'collections', + ComponentPath: '@payloadcms/ui/rsc#CollectionCards', + minWidth: 'full', + }) + sanitizedConfig.admin!.dashboard.defaultLayout ??= [ + { + widgetSlug: 'collections', + width: 'full', + } satisfies WidgetInstance, + ] // add default user collection if none provided if (!sanitizedConfig?.admin?.user) { diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index ffe355b7273..5941e5090fd 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -736,6 +736,53 @@ export type AfterErrorHook = ( args: AfterErrorHookArgs, ) => AfterErrorResult | Promise +export type WidgetWidth = 'full' | 'large' | 'medium' | 'small' | 'x-large' | 'x-small' + +export type Widget = { + ComponentPath: string + /** + * Human-friendly label for the widget. + * Supports i18n by passing an object with locale keys, or a function with `t` for translations. + * If not provided, the label will be auto-generated from the slug. + */ + label?: LabelFunction | StaticLabel + maxWidth?: WidgetWidth + minWidth?: WidgetWidth + slug: string + // TODO: Add fields + // fields?: Field[] + // Maybe: + // ImageURL?: string // similar to Block +} + +/** + * Client-side widget type with resolved label (no functions). + */ +export type ClientWidget = { + label?: StaticLabel + maxWidth?: WidgetWidth + minWidth?: WidgetWidth + slug: string +} + +export type WidgetInstance = { + // TODO: should be inferred from Widget Fields + // data: Record + widgetSlug: string + width?: WidgetWidth +} + +export type DashboardConfig = { + defaultLayout?: + | ((args: { req: PayloadRequest }) => Array | Promise>) + | Array + widgets: Array +} + +export type SanitizedDashboardConfig = { + widgets: Array> +} + /** * This is the central configuration * @@ -859,6 +906,11 @@ export type Config = { } /** Extension point to add your custom data. Available in server and client. */ custom?: Record + /** + * Customize the dashboard widgets + * @experimental This prop is subject to change in future releases. + */ + dashboard?: DashboardConfig /** Global date format that will be used for all dates in the Admin panel. Any valid date-fns format pattern can be used. */ dateFormat?: string /** diff --git a/packages/payload/src/index.ts b/packages/payload/src/index.ts index c9a5f123956..2f15a70d753 100644 --- a/packages/payload/src/index.ts +++ b/packages/payload/src/index.ts @@ -119,6 +119,7 @@ import { type Options as UpdateGlobalOptions, } from './globals/operations/local/update.js' export type * from './admin/types.js' +export { EntityType } from './admin/views/dashboard.js' import type { SupportedLanguages } from '@payloadcms/translations' import { Cron } from 'croner' diff --git a/packages/translations/src/clientKeys.ts b/packages/translations/src/clientKeys.ts index 13711a51baa..b7860873a71 100644 --- a/packages/translations/src/clientKeys.ts +++ b/packages/translations/src/clientKeys.ts @@ -62,6 +62,10 @@ export const clientTranslationKeys = createClientTranslationKeys([ 'authentication:verifyUser', 'authentication:youAreInactive', + 'dashboard:addWidget', + 'dashboard:deleteWidget', + 'dashboard:searchWidgets', + 'error:autosaving', 'error:correctInvalidFields', 'error:deletingTitle', diff --git a/packages/translations/src/languages/ar.ts b/packages/translations/src/languages/ar.ts index d2489b866af..622bfdc880e 100644 --- a/packages/translations/src/languages/ar.ts +++ b/packages/translations/src/languages/ar.ts @@ -79,6 +79,11 @@ export const arTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'إن لم تطلب هذا ، يرجى تجاهل هذا البريد الإلكتروني وستبقى كلمة مرورك ذاتها بدون تغيير.', }, + dashboard: { + addWidget: 'أضف الواجهة البيانية', + deleteWidget: 'حذف الودجت {{id}}', + searchWidgets: 'ابحث عن الأدوات...', + }, error: { accountAlreadyActivated: 'تم تفعيل هذا الحساب بالفعل.', autosaving: 'حدثت مشكلة أثناء حفظ هذا المستند تلقائيًا.', diff --git a/packages/translations/src/languages/az.ts b/packages/translations/src/languages/az.ts index 936f0c8e3d9..4a41727b705 100644 --- a/packages/translations/src/languages/az.ts +++ b/packages/translations/src/languages/az.ts @@ -79,6 +79,11 @@ export const azTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Əgər siz bunu tələb etməmisinizsə, lütfən, bu e-poçtu nəzərə almayın və şifrəniz dəyişilməz qalacaq.', }, + dashboard: { + addWidget: 'Vidjet əlavə et', + deleteWidget: 'Vidgeti silin {{id}}', + searchWidgets: 'Widgetləri axtarın...', + }, error: { accountAlreadyActivated: 'Bu hesab artıq aktivləşdirilib.', autosaving: 'Bu sənədin avto yadda saxlanılması zamanı problem yarandı.', diff --git a/packages/translations/src/languages/bg.ts b/packages/translations/src/languages/bg.ts index 421fd617702..71830c1f18c 100644 --- a/packages/translations/src/languages/bg.ts +++ b/packages/translations/src/languages/bg.ts @@ -79,6 +79,11 @@ export const bgTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Ако не си заявил това, игнорирай този имейл и паролата ти ще остане непроменена.', }, + dashboard: { + addWidget: 'Добави джаджа', + deleteWidget: 'Изтрийте джаджа {{id}}', + searchWidgets: 'Търсене на джаджи...', + }, error: { accountAlreadyActivated: 'Този профил вече е активиран.', autosaving: 'Имаше проблем в автоматичното запазване на този документ.', diff --git a/packages/translations/src/languages/bnBd.ts b/packages/translations/src/languages/bnBd.ts index 9dc5a005781..a0bd97d16af 100644 --- a/packages/translations/src/languages/bnBd.ts +++ b/packages/translations/src/languages/bnBd.ts @@ -79,6 +79,11 @@ export const bnBdTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'আপনি যদি এটি অনুরোধ না করে থাকেন, তাহলে এই ইমেইলটি উপেক্ষা করুন এবং আপনার পাসওয়ার্ড অপরিবর্তিত থাকবে।', }, + dashboard: { + addWidget: 'উইজেট যোগ করুন', + deleteWidget: 'উইজেট মুছে ফেলুন {{id}}', + searchWidgets: 'উইজেটগুলি অনুসন্ধান করুন...', + }, error: { accountAlreadyActivated: 'এই অ্যাকাউন্ট ইতিমধ্যে সক্রিয় করা হয়েছে।', autosaving: 'এই ডকুমেন্টটি স্বয়ংক্রিয়ভাবে সংরক্ষণ করার সময় একটি সমস্যা হয়েছে।', diff --git a/packages/translations/src/languages/bnIn.ts b/packages/translations/src/languages/bnIn.ts index 02c8a573aff..73ed878c4dd 100644 --- a/packages/translations/src/languages/bnIn.ts +++ b/packages/translations/src/languages/bnIn.ts @@ -79,6 +79,11 @@ export const bnInTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'আপনি যদি এটি অনুরোধ না করে থাকেন, তাহলে এই ইমেইলটি উপেক্ষা করুন এবং আপনার পাসওয়ার্ড অপরিবর্তিত থাকবে।', }, + dashboard: { + addWidget: 'উইজেট যোগ করুন', + deleteWidget: 'উইজেট মুছুন {{id}}', + searchWidgets: 'উইজেট অনুসন্ধান করুন...', + }, error: { accountAlreadyActivated: 'এই অ্যাকাউন্ট ইতিমধ্যে সক্রিয় করা হয়েছে।', autosaving: 'এই ডকুমেন্টটি স্বয়ংক্রিয়ভাবে সংরক্ষণ করার সময় একটি সমস্যা হয়েছে।', diff --git a/packages/translations/src/languages/ca.ts b/packages/translations/src/languages/ca.ts index 303739fd9b4..53521d2708f 100644 --- a/packages/translations/src/languages/ca.ts +++ b/packages/translations/src/languages/ca.ts @@ -79,6 +79,11 @@ export const caTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Si no has sol·licitat això, ignora aquest correu i la teva contrasenya romandrà inalterada.', }, + dashboard: { + addWidget: 'Afegeix Widget', + deleteWidget: 'Esborra el widget {{id}}', + searchWidgets: 'Cerca de ginys...', + }, error: { accountAlreadyActivated: 'Aquest compte ja ha estat activat.', autosaving: "Hi ha hagut un problema mentre s'estava desant automàticament aquest document.", diff --git a/packages/translations/src/languages/cs.ts b/packages/translations/src/languages/cs.ts index 053a652374f..2cb4be7133d 100644 --- a/packages/translations/src/languages/cs.ts +++ b/packages/translations/src/languages/cs.ts @@ -79,6 +79,11 @@ export const csTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Pokud jste o to nepožádali, ignorujte prosím tento e-mail a vaše heslo zůstane nezměněno.', }, + dashboard: { + addWidget: 'Přidat widget', + deleteWidget: 'Odstranit widget {{id}}', + searchWidgets: 'Hledat widgety...', + }, error: { accountAlreadyActivated: 'Tento účet již byl aktivován.', autosaving: 'Při automatickém ukládání tohoto dokumentu došlo k chybě.', diff --git a/packages/translations/src/languages/da.ts b/packages/translations/src/languages/da.ts index c43201590a7..e6dc3147cbc 100644 --- a/packages/translations/src/languages/da.ts +++ b/packages/translations/src/languages/da.ts @@ -78,6 +78,11 @@ export const daTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Hvis du ikke har anmodet om dette, skal du blot ignorere denne e-mail, og din adgangskode vil forblive uændret', }, + dashboard: { + addWidget: 'Tilføj Widget', + deleteWidget: 'Slet widget {{id}}', + searchWidgets: 'Søg widgets...', + }, error: { accountAlreadyActivated: 'Denne konto er allerede blevet aktiveret.', autosaving: 'Der opstod et problem under autosaving af dette dokument.', diff --git a/packages/translations/src/languages/de.ts b/packages/translations/src/languages/de.ts index 554e1e93234..0228bedc551 100644 --- a/packages/translations/src/languages/de.ts +++ b/packages/translations/src/languages/de.ts @@ -81,6 +81,11 @@ export const deTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Solltest du dies nicht angefordert haben, ignoriere diese E-Mail und dein Passwort bleibt unverändert.', }, + dashboard: { + addWidget: 'Widget hinzufügen', + deleteWidget: 'Löschen Sie das Widget {{id}}', + searchWidgets: 'Suche Widgets...', + }, error: { accountAlreadyActivated: 'Dieses Benutzerkonto wurde bereits aktiviert', autosaving: 'Es gab ein Problem bei der automatischen Speicherung für dieses Dokument', diff --git a/packages/translations/src/languages/en.ts b/packages/translations/src/languages/en.ts index b9de79c864a..b877b69eacf 100644 --- a/packages/translations/src/languages/en.ts +++ b/packages/translations/src/languages/en.ts @@ -80,6 +80,11 @@ export const enTranslations = { youDidNotRequestPassword: 'If you did not request this, please ignore this email and your password will remain unchanged.', }, + dashboard: { + addWidget: 'Add Widget', + deleteWidget: 'Delete widget {{id}}', + searchWidgets: 'Search widgets...', + }, error: { accountAlreadyActivated: 'This account has already been activated.', autosaving: 'There was a problem while autosaving this document.', diff --git a/packages/translations/src/languages/es.ts b/packages/translations/src/languages/es.ts index abc3c1ed621..8e79b6bf496 100644 --- a/packages/translations/src/languages/es.ts +++ b/packages/translations/src/languages/es.ts @@ -79,6 +79,11 @@ export const esTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Si no solicitaste esto, por favor ignora este correo y tu contraseña permanecerá sin cambios.', }, + dashboard: { + addWidget: 'Agregar Widget', + deleteWidget: 'Eliminar widget {{id}}', + searchWidgets: 'Buscar widgets...', + }, error: { accountAlreadyActivated: 'Esta cuenta ya fue activada.', autosaving: 'Hubo un problema al guardar automáticamente este documento.', diff --git a/packages/translations/src/languages/et.ts b/packages/translations/src/languages/et.ts index bf0737190de..8f0eecb6bb9 100644 --- a/packages/translations/src/languages/et.ts +++ b/packages/translations/src/languages/et.ts @@ -78,6 +78,11 @@ export const etTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Kui te seda ei taotlenud, ignoreerige seda e-kirja ja teie parool jääb muutmata.', }, + dashboard: { + addWidget: 'Lisa vidin', + deleteWidget: 'Kustuta vidin {{id}}', + searchWidgets: 'Otsi vidinaid...', + }, error: { accountAlreadyActivated: 'See konto on juba aktiveeritud.', autosaving: 'Dokumendi automaatsel salvestamisel tekkis probleem.', diff --git a/packages/translations/src/languages/fa.ts b/packages/translations/src/languages/fa.ts index 53c45e49990..58e6cebf81e 100644 --- a/packages/translations/src/languages/fa.ts +++ b/packages/translations/src/languages/fa.ts @@ -78,6 +78,11 @@ export const faTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'اگر شما درخواست بازنشانی رمز عبور نداده‌اید، این ایمیل را نادیده بگیرید. رمز عبور شما تغییری نخواهد کرد.', }, + dashboard: { + addWidget: 'اضافه کردن ویجت', + deleteWidget: 'حذف ابزارک {{id}}', + searchWidgets: 'جستجوی ابزارک‌ها...', + }, error: { accountAlreadyActivated: 'این حساب کاربری قبلاً فعال شده است.', autosaving: 'هنگام ذخیره خودکار این صفحه، خطایی رخ داد.', diff --git a/packages/translations/src/languages/fr.ts b/packages/translations/src/languages/fr.ts index 2160536dc17..fd260a4fa45 100644 --- a/packages/translations/src/languages/fr.ts +++ b/packages/translations/src/languages/fr.ts @@ -81,6 +81,11 @@ export const frTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Si vous ne l’avez pas demandé, veuillez ignorer cet e-mail et votre mot de passe restera inchangé.', }, + dashboard: { + addWidget: 'Ajouter un Widget', + deleteWidget: 'Supprimer le widget {{id}}', + searchWidgets: 'Rechercher des widgets...', + }, error: { accountAlreadyActivated: 'Ce compte a déjà été activé.', autosaving: 'Un problème est survenu lors de l’enregistrement automatique de ce document.', diff --git a/packages/translations/src/languages/he.ts b/packages/translations/src/languages/he.ts index 7784e14e56f..8bc3e9f197b 100644 --- a/packages/translations/src/languages/he.ts +++ b/packages/translations/src/languages/he.ts @@ -78,6 +78,11 @@ export const heTranslations: DefaultTranslationsObject = { 'קיבלת הודעה זו מכיוון שאתה (או מישהו אחר) ביקשת לאפס את הסיסמה של החשבון שלך. אנא לחץ על הקישור הבא או הדבק אותו בשורת הכתובת בדפדפן שלך כדי להשלים את התהליך:', youDidNotRequestPassword: 'אם לא ביקשת זאת, אנא התעלם מההודעה והסיסמה שלך תישאר ללא שינוי.', }, + dashboard: { + addWidget: "הוסף וידג'ט", + deleteWidget: "מחק וידג'ט {{id}}", + searchWidgets: "חפש ווידג'טים...", + }, error: { accountAlreadyActivated: 'חשבון זה כבר הופעל.', autosaving: 'אירעה בעיה בזמן שמירה אוטומטית של מסמך זה.', diff --git a/packages/translations/src/languages/hr.ts b/packages/translations/src/languages/hr.ts index aba77430410..9fac6d17eb5 100644 --- a/packages/translations/src/languages/hr.ts +++ b/packages/translations/src/languages/hr.ts @@ -80,6 +80,11 @@ export const hrTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Ako niste zatražili ovo, molimo ignorirajte ovaj e-mail i Vaša će lozinka ostati nepromijenjena.', }, + dashboard: { + addWidget: 'Dodaj widget', + deleteWidget: 'Izbriši widget {{id}}', + searchWidgets: 'Pretraži widgete...', + }, error: { accountAlreadyActivated: 'Ovaj račun je već aktiviran.', autosaving: 'Nastao je problem pri automatskom spremanju ovog dokumenta.', diff --git a/packages/translations/src/languages/hu.ts b/packages/translations/src/languages/hu.ts index f7f697d583b..e3ced60da96 100644 --- a/packages/translations/src/languages/hu.ts +++ b/packages/translations/src/languages/hu.ts @@ -81,6 +81,11 @@ export const huTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Ha nem Ön kérte ezt, kérjük, hagyja figyelmen kívül ezt az e-mailt, és jelszava változatlan marad.', }, + dashboard: { + addWidget: 'Adjon hozzá widgetet', + deleteWidget: 'Törölje a(z) {{id}} widgetet', + searchWidgets: 'Keresés widgetek...', + }, error: { accountAlreadyActivated: 'Ez a fiók már aktiválva van.', autosaving: 'Hiba történt a dokumentum automatikus mentése közben.', diff --git a/packages/translations/src/languages/hy.ts b/packages/translations/src/languages/hy.ts index f7e87b6b57e..98cb504eaf2 100644 --- a/packages/translations/src/languages/hy.ts +++ b/packages/translations/src/languages/hy.ts @@ -79,6 +79,11 @@ export const hyTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Եթե Դուք չեք ուղարկել հարցումը, խնդրում ենք անտեսել այս էլ. նամակը, և Ձեր գաղտնաբառը կմնա անփոփոխ։', }, + dashboard: { + addWidget: 'Ավելացնել վիճակագրություն', + deleteWidget: 'Ջնջել վիդջեթը {{id}}', + searchWidgets: 'Որոնել վիջեթներ...', + }, error: { accountAlreadyActivated: 'Այս հաշիվն արդեն ակտիվացված է։', autosaving: 'Այս փաստաթղթի ավտոմատ պահպանման ժամանակ խնդիր է առաջացել։', diff --git a/packages/translations/src/languages/id.ts b/packages/translations/src/languages/id.ts index 35a913c5c41..10637ee86bf 100644 --- a/packages/translations/src/languages/id.ts +++ b/packages/translations/src/languages/id.ts @@ -80,6 +80,11 @@ export const idTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Jika Anda tidak meminta ini, harap abaikan email ini dan kata sandi Anda akan tetap tidak berubah.', }, + dashboard: { + addWidget: 'Tambah Widget', + deleteWidget: 'Hapus widget {{id}}', + searchWidgets: 'Cari widget...', + }, error: { accountAlreadyActivated: 'Akun ini sudah diaktifkan.', autosaving: 'Terjadi masalah saat menyimpan otomatis dokumen ini.', diff --git a/packages/translations/src/languages/is.ts b/packages/translations/src/languages/is.ts index 4f23d6ef316..46adfbe7481 100644 --- a/packages/translations/src/languages/is.ts +++ b/packages/translations/src/languages/is.ts @@ -80,6 +80,11 @@ export const isTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Ef þú baðst ekki um þetta, vinsamlegast hunsaðu þennan tölvupóst og lykilorðið þitt verður óbreytt.', }, + dashboard: { + addWidget: 'Bæta við smáforriti', + deleteWidget: 'Eyða græju {{id}}', + searchWidgets: 'Leita að græjum...', + }, error: { accountAlreadyActivated: 'Þessi aðgangur hefur þegar verið virkjaður.', autosaving: 'Villa kom upp við sjálfvirka vistun á færslu.', diff --git a/packages/translations/src/languages/it.ts b/packages/translations/src/languages/it.ts index 0c64f7fca2f..1b1caf7ab55 100644 --- a/packages/translations/src/languages/it.ts +++ b/packages/translations/src/languages/it.ts @@ -79,6 +79,11 @@ export const itTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: "Se non l'hai richiesto, ignora questa email e la tua password rimarrà invariata.", }, + dashboard: { + addWidget: 'Aggiungi Widget', + deleteWidget: 'Elimina widget {{id}}', + searchWidgets: 'Cerca widget...', + }, error: { accountAlreadyActivated: 'Questo account è già stato attivato.', autosaving: diff --git a/packages/translations/src/languages/ja.ts b/packages/translations/src/languages/ja.ts index b148f8beb48..ded3759426d 100644 --- a/packages/translations/src/languages/ja.ts +++ b/packages/translations/src/languages/ja.ts @@ -80,6 +80,11 @@ export const jaTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'もし望まない場合は、このメールを無視してください。パスワードは変更されません。', }, + dashboard: { + addWidget: 'ウィジェットを追加する', + deleteWidget: 'ウィジェット{{id}}を削除します', + searchWidgets: 'ウィジェットを検索...', + }, error: { accountAlreadyActivated: 'このアカウントはすでに有効です。', autosaving: 'このデータを自動保存する際に問題が発生しました。', diff --git a/packages/translations/src/languages/ko.ts b/packages/translations/src/languages/ko.ts index cf9b9182f23..ba29e5aed30 100644 --- a/packages/translations/src/languages/ko.ts +++ b/packages/translations/src/languages/ko.ts @@ -79,6 +79,11 @@ export const koTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: '비밀번호 초기화를 요청하지 않았다면 이 이메일을 무시하시고 비밀번호를 변경하지 마세요.', }, + dashboard: { + addWidget: '위젯 추가', + deleteWidget: '위젯 {{id}} 삭제', + searchWidgets: '위젯 검색...', + }, error: { accountAlreadyActivated: '이 계정은 이미 활성화되었습니다.', autosaving: '이 문서를 자동 저장하는 중에 문제가 발생했습니다.', diff --git a/packages/translations/src/languages/lt.ts b/packages/translations/src/languages/lt.ts index 890dce150b7..3901e6bb915 100644 --- a/packages/translations/src/languages/lt.ts +++ b/packages/translations/src/languages/lt.ts @@ -80,6 +80,11 @@ export const ltTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Jei to neprašėte, prašome ignoruoti šį el. laišką ir jūsų slaptažodis išliks nepakeistas.', }, + dashboard: { + addWidget: 'Pridėti valdiklį', + deleteWidget: 'Ištrinti valdiklį {{id}}', + searchWidgets: 'Ieškokite valdiklių...', + }, error: { accountAlreadyActivated: 'Ši paskyra jau aktyvuota.', autosaving: 'Šio dokumento automatinio išsaugojimo metu kilo problema.', diff --git a/packages/translations/src/languages/lv.ts b/packages/translations/src/languages/lv.ts index 055852339b9..3ad2cb4fbdb 100644 --- a/packages/translations/src/languages/lv.ts +++ b/packages/translations/src/languages/lv.ts @@ -79,6 +79,11 @@ export const lvTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Ja neesat pieprasījis paroles atiestatīšanu, lūdzu, ignorējiet šo e-pastu, un parole paliks nemainīta.', }, + dashboard: { + addWidget: 'Pievienot logrīku', + deleteWidget: 'Dzēst logrīku {{id}}', + searchWidgets: 'Meklēt logrīkus...', + }, error: { accountAlreadyActivated: 'Šis konts jau ir aktivizēts.', autosaving: 'Radās problēma, automātiski saglabājot šo dokumentu.', diff --git a/packages/translations/src/languages/my.ts b/packages/translations/src/languages/my.ts index 9e3cc9ac3f2..ff0842455af 100644 --- a/packages/translations/src/languages/my.ts +++ b/packages/translations/src/languages/my.ts @@ -79,6 +79,11 @@ export const myTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'ယခု လုပ်ဆောင်ချက်ကို သင်မတောင်းဆိုထားပါက ဤအီးမေးလ်ကို လျစ်လျူရှုထားခြင်းဖြင့် သင့်စကားဝှက်သည် ပြောင်းလဲမည်မဟုတ်ပါ။', }, + dashboard: { + addWidget: 'Tambah Widget', + deleteWidget: 'Padam widget {{id}}', + searchWidgets: 'Cari widget...', + }, error: { accountAlreadyActivated: 'ဤအကောင့်ကို အသက်သွင်းပြီးဖြစ်သည်။', autosaving: 'ဖိုင်ကို အလိုအလျောက်သိမ်းဆည်းရာတွင် ပြဿနာတစ်ခုရှိနေသည်။', diff --git a/packages/translations/src/languages/nb.ts b/packages/translations/src/languages/nb.ts index c4b56a74823..b9fa8bf5cf0 100644 --- a/packages/translations/src/languages/nb.ts +++ b/packages/translations/src/languages/nb.ts @@ -79,6 +79,11 @@ export const nbTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Hvis du ikke har bedt om dette, kan du ignorere denne e-posten, og passordet ditt vil forbli uendret.', }, + dashboard: { + addWidget: 'Legg til widget', + deleteWidget: 'Slett widget {{id}}', + searchWidgets: 'Søk widgets...', + }, error: { accountAlreadyActivated: 'Denne kontoen er allerede aktivert.', autosaving: 'Det oppstod et problem under automatisk lagring av dokumentet.', diff --git a/packages/translations/src/languages/nl.ts b/packages/translations/src/languages/nl.ts index b5d85b8fa87..2ac242afaf9 100644 --- a/packages/translations/src/languages/nl.ts +++ b/packages/translations/src/languages/nl.ts @@ -80,6 +80,11 @@ export const nlTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Als u dit niet heeft aangevraagd, negeer dan deze e-mail en uw wachtwoord zal ongewijzigd blijven.', }, + dashboard: { + addWidget: 'Widget toevoegen', + deleteWidget: 'Verwijder widget {{id}}', + searchWidgets: 'Zoek widgets...', + }, error: { accountAlreadyActivated: 'Dit account is al geactiveerd.', autosaving: 'Er is een probleem opgetreden bij het automatisch bewaren van dit document.', diff --git a/packages/translations/src/languages/pl.ts b/packages/translations/src/languages/pl.ts index 949402382a5..b84ae6b8a8a 100644 --- a/packages/translations/src/languages/pl.ts +++ b/packages/translations/src/languages/pl.ts @@ -79,6 +79,11 @@ export const plTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Jeśli nie prosiłeś o zmianę hasła, zignoruj tę wiadomość, a Twoje hasło pozostanie niezmienione.', }, + dashboard: { + addWidget: 'Dodaj Widżet', + deleteWidget: 'Usuń widget {{id}}', + searchWidgets: 'Szukaj widgetów...', + }, error: { accountAlreadyActivated: 'To konto zostało już aktywowane.', autosaving: 'Wystąpił problem podczas automatycznego zapisywania tego dokumentu.', diff --git a/packages/translations/src/languages/pt.ts b/packages/translations/src/languages/pt.ts index 283c4b08193..ca127d6f4bc 100644 --- a/packages/translations/src/languages/pt.ts +++ b/packages/translations/src/languages/pt.ts @@ -80,6 +80,11 @@ export const ptTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Se você não fez essa requisição, por favor ignore esse email e sua senha permanecerá igual.', }, + dashboard: { + addWidget: 'Adicionar Widget', + deleteWidget: 'Excluir widget {{id}}', + searchWidgets: 'Pesquisar widgets...', + }, error: { accountAlreadyActivated: 'Essa conta já foi ativada.', autosaving: 'Ocorreu um problema ao salvar automaticamente esse documento.', diff --git a/packages/translations/src/languages/ro.ts b/packages/translations/src/languages/ro.ts index 07a529e6dc1..c85f1913a99 100644 --- a/packages/translations/src/languages/ro.ts +++ b/packages/translations/src/languages/ro.ts @@ -81,6 +81,11 @@ export const roTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Dacă nu ați solicitat acest lucru, vă rugăm să ignorați acest email și parola dvs. va rămâne neschimbată.', }, + dashboard: { + addWidget: 'Adaugați widget', + deleteWidget: 'Ștergeți widget-ul {{id}}', + searchWidgets: 'Caută widgeturi...', + }, error: { accountAlreadyActivated: 'Acest cont a fost deja activat.', autosaving: 'A existat o problemă în timpul salvării automate a acestui document.', diff --git a/packages/translations/src/languages/rs.ts b/packages/translations/src/languages/rs.ts index d260d3c354e..f3373224568 100644 --- a/packages/translations/src/languages/rs.ts +++ b/packages/translations/src/languages/rs.ts @@ -80,6 +80,11 @@ export const rsTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Ако нисте затражили промену лозинке игноришите ову поруку и лозинка ће остати непромењена.', }, + dashboard: { + addWidget: 'Dodaj Widget', + deleteWidget: 'Obriši vidžet {{id}}', + searchWidgets: 'Pretraži widgete...', + }, error: { accountAlreadyActivated: 'Овај налог је већ активиран.', autosaving: 'Настао је проблем при аутоматском чувању овог документа.', diff --git a/packages/translations/src/languages/rsLatin.ts b/packages/translations/src/languages/rsLatin.ts index 45180a8fed6..0d45fa43778 100644 --- a/packages/translations/src/languages/rsLatin.ts +++ b/packages/translations/src/languages/rsLatin.ts @@ -80,6 +80,11 @@ export const rsLatinTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Ako niste zatražili promenu lozinke ignorišite ovu poruku i lozinka će ostati nepromenjena.', }, + dashboard: { + addWidget: 'Dodaj widget', + deleteWidget: 'Obriši widget {{id}}', + searchWidgets: 'Pretraži dodatke...', + }, error: { accountAlreadyActivated: 'Ovaj nalog je već aktiviran.', autosaving: 'Nastao je problem pri automatskom čuvanju ovog dokumenta.', diff --git a/packages/translations/src/languages/ru.ts b/packages/translations/src/languages/ru.ts index 5abd777ad42..80d835e3ee4 100644 --- a/packages/translations/src/languages/ru.ts +++ b/packages/translations/src/languages/ru.ts @@ -80,6 +80,11 @@ export const ruTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Если вы не запрашивали этого, пожалуйста, проигнорируйте это письмо, и ваш пароль останется неизменным.', }, + dashboard: { + addWidget: 'Добавить виджет', + deleteWidget: 'Удалить виджет {{id}}', + searchWidgets: 'Поиск виджетов...', + }, error: { accountAlreadyActivated: 'Этот аккаунт уже был активирован.', autosaving: 'При автосохранении этого документа возникла проблема.', diff --git a/packages/translations/src/languages/sk.ts b/packages/translations/src/languages/sk.ts index fdccf2e07e7..e06bddc422c 100644 --- a/packages/translations/src/languages/sk.ts +++ b/packages/translations/src/languages/sk.ts @@ -80,6 +80,11 @@ export const skTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Ak ste o to nepožiadali, ignorujte prosím tento e-mail a vaše heslo zostane nezmenené.', }, + dashboard: { + addWidget: 'Pridať Widget', + deleteWidget: 'Odstrániť widget {{id}}', + searchWidgets: 'Hľadať doplnky...', + }, error: { accountAlreadyActivated: 'Tento účet už bol aktivovaný.', autosaving: 'Pri automatickom ukladaní tohto dokumentu došlo k chybe.', diff --git a/packages/translations/src/languages/sl.ts b/packages/translations/src/languages/sl.ts index fcc16d389a3..271b56da3c7 100644 --- a/packages/translations/src/languages/sl.ts +++ b/packages/translations/src/languages/sl.ts @@ -79,6 +79,11 @@ export const slTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Če tega niste zahtevali, prezrite to e-pošto in vaše geslo bo ostalo nespremenjeno.', }, + dashboard: { + addWidget: 'Dodaj pripomoček', + deleteWidget: 'Izbriši pripomoček {{id}}', + searchWidgets: 'Išči gradnike...', + }, error: { accountAlreadyActivated: 'Ta račun je že aktiviran.', autosaving: 'Pri samodejnem shranjevanju tega dokumenta je prišlo do težave.', diff --git a/packages/translations/src/languages/sv.ts b/packages/translations/src/languages/sv.ts index 8ae4b398cb2..3801c6ab6bf 100644 --- a/packages/translations/src/languages/sv.ts +++ b/packages/translations/src/languages/sv.ts @@ -79,6 +79,11 @@ export const svTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Om du inte begärde detta, ignorera detta e-postmeddelande och ditt lösenord kommer att förbli oförändrat.', }, + dashboard: { + addWidget: 'Lägg till Widget', + deleteWidget: 'Radera widget {{id}}', + searchWidgets: 'Sök widgetar...', + }, error: { accountAlreadyActivated: 'Detta konto har redan aktiverats', autosaving: 'Det uppstod ett problem när det här dokumentet skulle sparas automatiskt.', diff --git a/packages/translations/src/languages/ta.ts b/packages/translations/src/languages/ta.ts index 611d15b2c02..7a3f4397151 100644 --- a/packages/translations/src/languages/ta.ts +++ b/packages/translations/src/languages/ta.ts @@ -78,6 +78,11 @@ export const taTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'இதை நீங்கள் கோரவில்லை என்றால், இந்த மின்னஞ்சலை புறக்கணிக்கவும். உங்கள் கடவுச்சொல் மாறாது இருக்கும்.', }, + dashboard: { + addWidget: 'விக்கெட் சேர்', + deleteWidget: '{{id}} விட்ஜெடை நீக்கு', + searchWidgets: 'தேடல் கருவிகள்...', + }, error: { accountAlreadyActivated: 'இந்த கணக்கு ஏற்கனவே செயல்படுத்தப்பட்டுள்ளது.', autosaving: 'இந்த ஆவணத்தை தானாகச் சேமிக்கும் போது ஒரு பிரச்சனை ஏற்பட்டது.', diff --git a/packages/translations/src/languages/th.ts b/packages/translations/src/languages/th.ts index 551746e46fc..e261b357b3e 100644 --- a/packages/translations/src/languages/th.ts +++ b/packages/translations/src/languages/th.ts @@ -78,6 +78,11 @@ export const thTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'หากคุณไม่ได้ร้องขอให้มีการรีเซ็ตรหัสผ่าน คุณสามารถเพิกเฉยข้อความนี้ได้ โดยรหัสผ่านของคุณจะคงอยู่เช่นเดิม', }, + dashboard: { + addWidget: 'เพิ่มวิดเจ็ต', + deleteWidget: 'ลบวิดเจ็ต {{id}}', + searchWidgets: 'ค้นหาวิดเจ็ต...', + }, error: { accountAlreadyActivated: 'บัญชีนี้ถูกเปิดใช้งานไปแล้ว', autosaving: 'เกิดปัญหาระหว่างการบันทึกเอกสารอัตโนมัติ', diff --git a/packages/translations/src/languages/tr.ts b/packages/translations/src/languages/tr.ts index 7570c21a9e3..16fa30f268f 100644 --- a/packages/translations/src/languages/tr.ts +++ b/packages/translations/src/languages/tr.ts @@ -80,6 +80,11 @@ export const trTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Eğer bu işlemi siz gerçekleştirmediyseniz bu e-postayı görmezden gelebilirsiniz.', }, + dashboard: { + addWidget: 'Widget Ekle', + deleteWidget: "Widget'i sil {{id}}", + searchWidgets: "Arama widget'ları...", + }, error: { accountAlreadyActivated: 'Hesap zaten etkinleştirildi.', autosaving: 'Otomatik kaydetme başarısız oldu', diff --git a/packages/translations/src/languages/uk.ts b/packages/translations/src/languages/uk.ts index 64dd2f5dc4e..4327fec1cab 100644 --- a/packages/translations/src/languages/uk.ts +++ b/packages/translations/src/languages/uk.ts @@ -80,6 +80,11 @@ export const ukTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Якщо ви не сторювали цей запит, будь ласка, проігноруйте це повідомлення', }, + dashboard: { + addWidget: 'Додати віджет', + deleteWidget: 'Видалити віджет {{id}}', + searchWidgets: 'Пошук віджетів...', + }, error: { accountAlreadyActivated: 'Цей обліковий запис вже активований', autosaving: 'Виникла проблема під час автозбереження цього документа.', diff --git a/packages/translations/src/languages/vi.ts b/packages/translations/src/languages/vi.ts index 4ae865828f8..6bb46ec7590 100644 --- a/packages/translations/src/languages/vi.ts +++ b/packages/translations/src/languages/vi.ts @@ -79,6 +79,11 @@ export const viTranslations: DefaultTranslationsObject = { youDidNotRequestPassword: 'Nếu bạn không phải là người yêu cầu thay đổi mật khẩu, xin hãy bỏ qua tin nhắn này và mật khẩu của bạn sẽ được giữ nguyên.', }, + dashboard: { + addWidget: 'Thêm Widget', + deleteWidget: 'Xóa widget {{id}}', + searchWidgets: 'Tìm kiếm các widget...', + }, error: { accountAlreadyActivated: 'Lỗi - Tài khoản này đã được kích hoạt.', autosaving: 'Lỗi - Đã xảy ra vấn đề khi tự động sao lưu bản tài liệu này.', diff --git a/packages/translations/src/languages/zh.ts b/packages/translations/src/languages/zh.ts index a7c64e67bfc..312f9fbe96e 100644 --- a/packages/translations/src/languages/zh.ts +++ b/packages/translations/src/languages/zh.ts @@ -77,6 +77,11 @@ export const zhTranslations: DefaultTranslationsObject = { '您收到此邮件是因为您(或其他人)已请求重置您账号的密码。请点击以下链接,或将其粘贴到您的浏览器中以完成该过程:', youDidNotRequestPassword: '如果您没有要求这样做,请忽略这封邮件,您的密码将保持不变。', }, + dashboard: { + addWidget: '添加小部件', + deleteWidget: '删除小部件 {{id}}', + searchWidgets: '搜索小工具...', + }, error: { accountAlreadyActivated: '该账号已被激活。', autosaving: '自动保存该文档时出现了问题。', diff --git a/packages/translations/src/languages/zhTw.ts b/packages/translations/src/languages/zhTw.ts index a14c7623756..afb0bcd1d0c 100644 --- a/packages/translations/src/languages/zhTw.ts +++ b/packages/translations/src/languages/zhTw.ts @@ -76,6 +76,11 @@ export const zhTwTranslations: DefaultTranslationsObject = { '您會收到這封郵件是因為您(或其他人)請求重設此帳戶的密碼。請點選以下連結,或將該連結貼至瀏覽器以完成操作:', youDidNotRequestPassword: '如果這不是您本人操作,請忽略這封郵件,您的密碼將不會改變。', }, + dashboard: { + addWidget: '添加小工具', + deleteWidget: '刪除小工具 {{id}}', + searchWidgets: '搜索小工具...', + }, error: { accountAlreadyActivated: '此帳戶已啟用。', autosaving: '自動儲存文件時發生問題。', diff --git a/packages/ui/src/elements/AppHeader/index.scss b/packages/ui/src/elements/AppHeader/index.scss index 28b8958d895..e72901c193b 100644 --- a/packages/ui/src/elements/AppHeader/index.scss +++ b/packages/ui/src/elements/AppHeader/index.scss @@ -97,7 +97,6 @@ &__step-nav-wrapper { flex-grow: 0; - overflow: auto; display: flex; width: 100%; diff --git a/packages/ui/src/elements/ItemsDrawer/ItemSearch/index.scss b/packages/ui/src/elements/ItemsDrawer/ItemSearch/index.scss new file mode 100644 index 00000000000..649938b1748 --- /dev/null +++ b/packages/ui/src/elements/ItemsDrawer/ItemSearch/index.scss @@ -0,0 +1,38 @@ +@import '../../../scss/styles.scss'; + +$icon-width: base(2); +$icon-margin: base(0.25); + +@layer payload-default { + .item-search { + position: sticky; + top: 0; + display: flex; + width: 100%; + align-items: center; + z-index: 1; + + &__input { + @include formInput; + } + + .icon--search { + position: absolute; + top: 50%; + transform: translate3d(0, -50%, 0); + right: 0; + width: $icon-width; + margin: 0 $icon-margin; + + .stroke { + stroke: var(--theme-elevation-300); + } + } + + @include mid-break { + &__input { + margin-bottom: 0; + } + } + } +} diff --git a/packages/ui/src/elements/ItemsDrawer/ItemSearch/index.tsx b/packages/ui/src/elements/ItemsDrawer/ItemSearch/index.tsx new file mode 100644 index 00000000000..4209c7f17f1 --- /dev/null +++ b/packages/ui/src/elements/ItemsDrawer/ItemSearch/index.tsx @@ -0,0 +1,38 @@ +'use client' +import React, { useId } from 'react' + +import { SearchIcon } from '../../../icons/Search/index.js' +import './index.scss' + +const baseClass = 'item-search' + +export type Props = { + readonly placeholder?: string + readonly setSearchTerm: (term: string) => void +} + +export const ItemSearch: React.FC = ({ placeholder, setSearchTerm }) => { + const inputId = useId() + const labelId = `${inputId}-label` + + const handleChange = (e: React.ChangeEvent) => { + setSearchTerm(e.target.value) + } + + return ( +
+ + + +
+ ) +} diff --git a/packages/ui/src/elements/ItemsDrawer/index.scss b/packages/ui/src/elements/ItemsDrawer/index.scss new file mode 100644 index 00000000000..b5192a7d13d --- /dev/null +++ b/packages/ui/src/elements/ItemsDrawer/index.scss @@ -0,0 +1,102 @@ +@import '../../scss/styles.scss'; + +@layer payload-default { + .items-drawer { + &__items-wrapper { + padding-top: base(1.5); + } + + &__items { + position: relative; + padding: 0; + list-style: none; + display: grid; + grid-template-columns: repeat(6, 1fr); + gap: base(1); + } + + &__default-image { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + aspect-ratio: 3 / 2; + overflow: hidden; + + img, + svg { + width: 100%; + height: 100%; + object-fit: cover; + } + } + + &__item-groups { + padding: 0; + display: flex; + flex-direction: column; + gap: base(1.5); + } + + &__item-group { + list-style: none; + } + + &__item-group-label { + padding-bottom: base(0.5); + } + + &__item-group-none { + order: 1; + padding-top: base(1.5); + border-top: 1px solid var(--theme-border-color); + + &:only-child { + padding-top: 0; + border-top: 0; + } + } + + @include large-break { + &__items { + grid-template-columns: repeat(5, 1fr); + } + } + + @include mid-break { + &__items-wrapper { + padding-top: base(1.75); + } + + &__items { + grid-template-columns: repeat(3, 1fr); + } + + &__item-groups { + gap: base(1.75); + } + + &__item-group-none { + padding-top: base(1.75); + } + } + + @include small-break { + &__items-wrapper { + padding-top: base(0.75); + } + + &__items { + grid-template-columns: repeat(2, 1fr); + } + + &__item-groups { + gap: base(0.75); + } + + &__item-group-none { + padding-top: base(0.75); + } + } + } +} diff --git a/packages/ui/src/elements/ItemsDrawer/index.tsx b/packages/ui/src/elements/ItemsDrawer/index.tsx new file mode 100644 index 00000000000..18371d4802c --- /dev/null +++ b/packages/ui/src/elements/ItemsDrawer/index.tsx @@ -0,0 +1,226 @@ +'use client' +import type { I18nClient } from '@payloadcms/translations' +import type { ClientBlock, ClientWidget, Labels } from 'payload' + +import { useModal } from '@faceless-ui/modal' +import { getTranslation } from '@payloadcms/translations' +import { toWords } from 'payload/shared' +import React, { useEffect, useMemo, useState } from 'react' + +import { DefaultBlockImage } from '../../graphics/DefaultBlockImage/index.js' +import { useConfig } from '../../providers/Config/index.js' +import { useTranslation } from '../../providers/Translation/index.js' +import { Drawer } from '../Drawer/index.js' +import { ThumbnailCard } from '../ThumbnailCard/index.js' +import './index.scss' +import { ItemSearch } from './ItemSearch/index.js' + +export type DrawerItem = ClientBlock | ClientWidget + +export type ItemsDrawerProps = { + readonly addRowIndex?: number + readonly drawerSlug: string + readonly items: (DrawerItem | string)[] + readonly labels?: Labels + readonly onItemClick: (item: DrawerItem, index?: number) => Promise | void + readonly searchPlaceholder?: string + readonly title?: string +} + +const baseClass = 'items-drawer' + +const getItemLabel = (item: DrawerItem, i18n: I18nClient): string => { + // Handle ClientBlock + if ('labels' in item && item.labels?.singular) { + if (typeof item.labels.singular === 'string') { + return item.labels.singular.toLowerCase() + } + if (typeof item.labels.singular === 'object') { + return getTranslation(item.labels.singular, i18n).toLowerCase() + } + } + + // Handle ClientWidget with label (already resolved from function on server) + if ('label' in item && item.label) { + if (typeof item.label === 'string') { + return item.label.toLowerCase() + } + if (typeof item.label === 'object') { + return getTranslation(item.label, i18n).toLowerCase() + } + } + + // Fallback to slug + if ('slug' in item) { + return toWords(item.slug).toLowerCase() + } + + return '' +} + +const getItemSlug = (item: DrawerItem): string => { + return item.slug +} + +const getItemImageInfo = (item: DrawerItem) => { + if ('imageURL' in item) { + return { + imageAltText: item.imageAltText, + imageURL: item.imageURL, + } + } + return { imageAltText: undefined, imageURL: undefined } +} + +const getItemDisplayLabel = (item: DrawerItem, i18n: I18nClient): string => { + // Handle ClientBlock + if ('labels' in item && item.labels?.singular) { + return getTranslation(item.labels.singular, i18n) + } + + // Handle ClientWidget with label (already resolved from function on server) + if ('label' in item && item.label) { + if (typeof item.label === 'string') { + return item.label + } + if (typeof item.label === 'object') { + return getTranslation(item.label, i18n) + } + } + + // Fallback to slug - convert to human-readable label + return toWords(item.slug) +} + +export const ItemsDrawer: React.FC = (props) => { + const { addRowIndex, drawerSlug, items, labels, onItemClick, searchPlaceholder, title } = props + + const [searchTerm, setSearchTerm] = useState('') + const [filteredItems, setFilteredItems] = useState(items) + const { closeModal, isModalOpen } = useModal() + const { i18n, t } = useTranslation() + const { config } = useConfig() + + const itemGroups = useMemo(() => { + const groups: Record = { + _none: [], + } + filteredItems.forEach((item) => { + if (typeof item === 'object' && 'admin' in item && item.admin?.group) { + const group = item.admin.group + const label = typeof group === 'string' ? group : getTranslation(group, i18n) + + if (Object.hasOwn(groups, label)) { + groups[label].push(item) + } else { + groups[label] = [item] + } + } else { + groups._none.push(item) + } + }) + return groups + }, [filteredItems, i18n]) + + useEffect(() => { + if (!isModalOpen(drawerSlug)) { + setSearchTerm('') + } + }, [isModalOpen, drawerSlug]) + + useEffect(() => { + const searchTermToUse = searchTerm.toLowerCase() + + const matchingItems = items?.reduce((matchedItems, _item) => { + let item: DrawerItem + + if (typeof _item === 'string') { + // Handle string references (for blocks) + item = config.blocksMap?.[_item] as DrawerItem + } else { + item = _item + } + + if (item) { + const itemLabel = getItemLabel(item, i18n) + if (itemLabel.includes(searchTermToUse)) { + matchedItems.push(item) + } + } + return matchedItems + }, [] as DrawerItem[]) + + setFilteredItems(matchingItems || []) + }, [searchTerm, items, i18n, config.blocksMap]) + + const finalTitle = + title || + (labels + ? t('fields:addLabel', { label: getTranslation(labels.singular, i18n) }) + : t('fields:addNew')) + + return ( + + +
+
    + {Object.entries(itemGroups).map(([groupLabel, groupItems]) => + !groupItems.length ? null : ( +
  • + {groupLabel !== '_none' && ( +

    {groupLabel}

    + )} +
      + {groupItems.map((_item, index) => { + const item = + typeof _item === 'string' ? (config.blocksMap?.[_item] as DrawerItem) : _item + + if (!item) { + return null + } + + const { imageAltText, imageURL } = getItemImageInfo(item) + const displayLabel = getItemDisplayLabel(item, i18n) + + return ( +
    • + { + void onItemClick(item, addRowIndex) + closeModal(drawerSlug) + }} + thumbnail={ +
      + {imageURL ? ( + {imageAltText} + ) : ( + + )} +
      + } + /> +
    • + ) + })} +
    +
  • + ), + )} +
+
+
+ ) +} diff --git a/packages/ui/src/elements/Link/index.tsx b/packages/ui/src/elements/Link/index.tsx index 8d7f95b30d1..2090851d9c3 100644 --- a/packages/ui/src/elements/Link/index.tsx +++ b/packages/ui/src/elements/Link/index.tsx @@ -62,15 +62,18 @@ export const Link: React.FC = ({ e.preventDefault() } - startRouteTransition(() => { - const url = typeof href === 'string' ? href : formatUrl(href) + const url = typeof href === 'string' ? href : formatUrl(href) + const navigate = () => { if (replace) { void router.replace(url, { scroll }) } else { void router.push(url, { scroll }) } - }) + } + + // Call startRouteTransition if available, otherwise navigate directly + startRouteTransition(navigate) }} ref={ref} {...rest} diff --git a/packages/ui/src/elements/StepNav/context.tsx b/packages/ui/src/elements/StepNav/context.tsx index 58f73868299..d6d619ca775 100644 --- a/packages/ui/src/elements/StepNav/context.tsx +++ b/packages/ui/src/elements/StepNav/context.tsx @@ -5,7 +5,15 @@ import type { ContextType } from './types.js' export const useStepNav = (): ContextType => use(Context) -export const Context = createContext({} as ContextType) +export const Context = createContext({ + setStepNav: () => { + if (process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line no-console + console.warn('StepNavProvider is missing; `setStepNav` is a no-op.') + } + }, + stepNav: [], +}) export const StepNavProvider: React.FC<{ children?: React.ReactNode }> = ({ children }) => { const [stepNav, setStepNav] = useState([]) diff --git a/packages/ui/src/elements/StepNav/index.scss b/packages/ui/src/elements/StepNav/index.scss index 1de8698382a..e5da8fb985e 100644 --- a/packages/ui/src/elements/StepNav/index.scss +++ b/packages/ui/src/elements/StepNav/index.scss @@ -61,7 +61,6 @@ span { max-width: base(8); text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; } diff --git a/packages/ui/src/exports/client/index.ts b/packages/ui/src/exports/client/index.ts index ac3bfaffbfe..4a72c734591 100644 --- a/packages/ui/src/exports/client/index.ts +++ b/packages/ui/src/exports/client/index.ts @@ -184,6 +184,7 @@ export { export { BlocksDrawer } from '../../fields/Blocks/BlocksDrawer/index.js' export { BlockSelector } from '../../fields/Blocks/BlockSelector/index.js' export { SectionTitle } from '../../fields/Blocks/SectionTitle/index.js' +export { ItemsDrawer } from '../../elements/ItemsDrawer/index.js' // fields export { HiddenField } from '../../fields/Hidden/index.js' diff --git a/packages/ui/src/exports/rsc/index.ts b/packages/ui/src/exports/rsc/index.ts index acb389fcd45..1979a8b3f4c 100644 --- a/packages/ui/src/exports/rsc/index.ts +++ b/packages/ui/src/exports/rsc/index.ts @@ -15,3 +15,4 @@ export { handlePreview } from '../../utilities/handlePreview.js' export { renderFilters, renderTable } from '../../utilities/renderTable.js' export { resolveFilterOptions } from '../../utilities/resolveFilterOptions.js' export { upsertPreferences } from '../../utilities/upsertPreferences.js' +export { CollectionCards } from '../../widgets/CollectionCards/index.js' diff --git a/packages/ui/src/exports/shared/index.ts b/packages/ui/src/exports/shared/index.ts index 540a2caf190..079bb26373f 100644 --- a/packages/ui/src/exports/shared/index.ts +++ b/packages/ui/src/exports/shared/index.ts @@ -14,6 +14,9 @@ export { findLocaleFromCode } from '../../utilities/findLocaleFromCode.js' export { formatAdminURL } from '../../utilities/formatAdminURL.js' export { formatDate } from '../../utilities/formatDocTitle/formatDateTitle.js' export { formatDocTitle } from '../../utilities/formatDocTitle/index.js' +export { getGlobalData } from '../../utilities/getGlobalData.js' +export { getNavGroups } from '../../utilities/getNavGroups.js' +export { getVisibleEntities } from '../../utilities/getVisibleEntities.js' export { type EntityToGroup, EntityType, diff --git a/packages/ui/src/providers/RouteTransition/index.tsx b/packages/ui/src/providers/RouteTransition/index.tsx index d454aebd2c2..06c529f65de 100644 --- a/packages/ui/src/providers/RouteTransition/index.tsx +++ b/packages/ui/src/providers/RouteTransition/index.tsx @@ -94,7 +94,12 @@ type RouteTransitionContextValue = { const RouteTransitionContext = React.createContext({ isTransitioning: false, - startRouteTransition: () => undefined, + // Default implementation: just call the callback directly (no transition animation) + startRouteTransition: (callback) => { + if (typeof callback === 'function') { + callback() + } + }, transitionProgress: 0, }) diff --git a/packages/ui/src/scss/app.scss b/packages/ui/src/scss/app.scss index 7e99e7c32b6..53677943a7b 100644 --- a/packages/ui/src/scss/app.scss +++ b/packages/ui/src/scss/app.scss @@ -190,6 +190,18 @@ color: currentColor; } + .sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; + } + .payload__modal-item { min-height: 100%; background: transparent; diff --git a/packages/ui/src/utilities/getGlobalData.ts b/packages/ui/src/utilities/getGlobalData.ts new file mode 100644 index 00000000000..712bd5fa23d --- /dev/null +++ b/packages/ui/src/utilities/getGlobalData.ts @@ -0,0 +1,61 @@ +import type { ClientUser, PayloadRequest, TypedUser } from 'payload' + +const globalLockDurationDefault = 300 + +export async function getGlobalData(req: PayloadRequest) { + const { + payload: { config }, + payload, + } = req + // Query locked global documents only if there are globals in the config + // This type is repeated from DashboardViewServerPropsOnly['globalData']. + // I thought about moving it to a payload to share it, but we're already + // exporting all the views props from the next package. + let globalData: Array<{ + data: { _isLocked: boolean; _lastEditedAt: string; _userEditing: ClientUser | number | string } + lockDuration?: number + slug: string + }> = [] + + if (config.globals.length > 0) { + const lockedDocuments = await payload.find({ + collection: 'payload-locked-documents', + depth: 1, + overrideAccess: false, + pagination: false, + req, + select: { + globalSlug: true, + updatedAt: true, + user: true, + }, + where: { + globalSlug: { + exists: true, + }, + }, + }) + + // Map over globals to include `lockDuration` and lock data for each global slug + globalData = config.globals.map((global) => { + const lockDuration = + typeof global.lockDocuments === 'object' + ? global.lockDocuments.duration + : globalLockDurationDefault + + const lockedDoc = lockedDocuments.docs.find((doc) => doc.globalSlug === global.slug) + + return { + slug: global.slug, + data: { + _isLocked: !!lockedDoc, + _lastEditedAt: (lockedDoc?.updatedAt as string) ?? null, + _userEditing: (lockedDoc?.user as { value?: TypedUser })?.value ?? null!, + }, + lockDuration, + } + }) + } + + return globalData +} diff --git a/packages/ui/src/utilities/getNavGroups.ts b/packages/ui/src/utilities/getNavGroups.ts new file mode 100644 index 00000000000..dcf41f346fd --- /dev/null +++ b/packages/ui/src/utilities/getNavGroups.ts @@ -0,0 +1,50 @@ +import type { SanitizedConfig, SanitizedPermissions, VisibleEntities } from 'payload' + +import { type I18nClient } from '@payloadcms/translations' + +import { EntityType } from './groupNavItems.js' +import { type EntityToGroup, groupNavItems } from './groupNavItems.js' + +/** @internal */ +export function getNavGroups( + permissions: SanitizedPermissions, + visibleEntities: VisibleEntities, + config: SanitizedConfig, + i18n: I18nClient, +) { + const collections = config.collections.filter( + (collection) => + permissions?.collections?.[collection.slug]?.read && + visibleEntities.collections.includes(collection.slug), + ) + + const globals = config.globals.filter( + (global) => + permissions?.globals?.[global.slug]?.read && visibleEntities.globals.includes(global.slug), + ) + + const navGroups = groupNavItems( + [ + ...(collections.map((collection) => { + const entityToGroup: EntityToGroup = { + type: EntityType.collection, + entity: collection, + } + + return entityToGroup + }) ?? []), + ...(globals.map((global) => { + const entityToGroup: EntityToGroup = { + type: EntityType.global, + entity: global, + } + + return entityToGroup + }) ?? []), + ], + permissions, + i18n, + ) + + return navGroups +} diff --git a/packages/ui/src/utilities/getVisibleEntities.ts b/packages/ui/src/utilities/getVisibleEntities.ts new file mode 100644 index 00000000000..f602fcbabeb --- /dev/null +++ b/packages/ui/src/utilities/getVisibleEntities.ts @@ -0,0 +1,25 @@ +import type { PayloadRequest, VisibleEntities } from 'payload' + +type Hidden = ((args: { user: unknown }) => boolean) | boolean + +function isHidden(hidden: Hidden | undefined, user: unknown): boolean { + if (typeof hidden === 'function') { + try { + return hidden({ user }) + } catch { + return true + } + } + return !!hidden +} + +export function getVisibleEntities({ req }: { req: PayloadRequest }): VisibleEntities { + return { + collections: req.payload.config.collections + .map(({ slug, admin: { hidden } }) => (!isHidden(hidden, req.user) ? slug : null)) + .filter(Boolean), + globals: req.payload.config.globals + .map(({ slug, admin: { hidden } }) => (!isHidden(hidden, req.user) ? slug : null)) + .filter(Boolean), + } +} diff --git a/packages/ui/src/utilities/groupNavItems.ts b/packages/ui/src/utilities/groupNavItems.ts index 7eb4b55c44d..cb42cd65c3e 100644 --- a/packages/ui/src/utilities/groupNavItems.ts +++ b/packages/ui/src/utilities/groupNavItems.ts @@ -8,6 +8,9 @@ import type { import { getTranslation } from '@payloadcms/translations' +/** + * @deprecated Import from `payload` instead + */ export enum EntityType { collection = 'collections', global = 'globals', diff --git a/packages/next/src/views/Dashboard/Default/index.scss b/packages/ui/src/widgets/CollectionCards/index.scss similarity index 91% rename from packages/next/src/views/Dashboard/Default/index.scss rename to packages/ui/src/widgets/CollectionCards/index.scss index 083c81f25d8..0330e9c2831 100644 --- a/packages/next/src/views/Dashboard/Default/index.scss +++ b/packages/ui/src/widgets/CollectionCards/index.scss @@ -1,13 +1,14 @@ @import '~@payloadcms/ui/scss'; @layer payload-default { - .dashboard { + .collections { + display: flex; width: 100%; --gap: var(--base); --cols: 5; &__wrap { - padding-bottom: var(--spacing-view-bottom); + width: 100%; display: flex; flex-direction: column; gap: var(--base); @@ -27,7 +28,7 @@ padding: 0; margin: 0; list-style: none; - gap: var(--gap); + gap: 12px; display: grid; grid-template-columns: repeat(var(--cols), 1fr); diff --git a/packages/ui/src/widgets/CollectionCards/index.tsx b/packages/ui/src/widgets/CollectionCards/index.tsx new file mode 100644 index 00000000000..27783410e7c --- /dev/null +++ b/packages/ui/src/widgets/CollectionCards/index.tsx @@ -0,0 +1,141 @@ +import type { WidgetServerProps } from 'payload' + +import { getTranslation } from '@payloadcms/translations' +import { EntityType, getAccessResults } from 'payload' +import { formatAdminURL } from 'payload/shared' +import React from 'react' + +import { Button } from '../../elements/Button/index.js' +import { Card } from '../../elements/Card/index.js' +import { Locked } from '../../elements/Locked/index.js' +import { getGlobalData } from '../../utilities/getGlobalData.js' +import { getNavGroups } from '../../utilities/getNavGroups.js' +import './index.scss' +import { getVisibleEntities } from '../../utilities/getVisibleEntities.js' + +const baseClass = 'collections' + +export async function CollectionCards(props: WidgetServerProps) { + const { i18n, payload, user } = props.req + const { admin: adminRoute } = payload.config.routes + const { t } = i18n + const permissions = await getAccessResults({ req: props.req }) + const visibleEntities = getVisibleEntities({ req: props.req }) + const globalData = await getGlobalData(props.req) + const { serverURL } = payload.config + + const navGroups = getNavGroups(permissions, visibleEntities, payload.config, i18n) + + return ( +
+
+ {!navGroups || navGroups?.length === 0 ? ( +

no nav groups....

+ ) : ( + navGroups.map(({ entities, label }, groupIndex) => { + return ( +
+

{label}

+
    + {entities.map(({ slug, type, label }, entityIndex) => { + let title: string + let buttonAriaLabel: string + let createHREF: string + let href: string + let hasCreatePermission: boolean + let isLocked = null + let userEditing = null + + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison + if (type === EntityType.collection) { + title = getTranslation(label, i18n) + + buttonAriaLabel = t('general:showAllLabel', { label: title }) + + href = formatAdminURL({ + adminRoute, + path: `/collections/${slug}`, + serverURL, + }) + + createHREF = formatAdminURL({ + adminRoute, + path: `/collections/${slug}/create`, + serverURL, + }) + + hasCreatePermission = permissions?.collections?.[slug]?.create + } + + // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison + if (type === EntityType.global) { + title = getTranslation(label, i18n) + + buttonAriaLabel = t('general:editLabel', { + label: getTranslation(label, i18n), + }) + + href = formatAdminURL({ + adminRoute, + path: `/globals/${slug}`, + }) + + // Find the lock status for the global + const globalLockData = globalData.find((global) => global.slug === slug) + if (globalLockData) { + isLocked = globalLockData.data._isLocked + userEditing = globalLockData.data._userEditing + + // Check if the lock is expired + const lockDuration = globalLockData?.lockDuration + const lastEditedAt = new Date(globalLockData.data?._lastEditedAt).getTime() + + const lockDurationInMilliseconds = lockDuration * 1000 + const lockExpirationTime = lastEditedAt + lockDurationInMilliseconds + + if (new Date().getTime() > lockExpirationTime) { + isLocked = false + userEditing = null + } + } + } + + return ( +
  • + + ) : // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison + hasCreatePermission && type === EntityType.collection ? ( +
  • + ) + })} +
+
+ ) + }) + )} +
+
+ ) +} diff --git a/payload-types.ts b/payload-types.ts index 1b22b04b70e..f640cd43358 100644 --- a/payload-types.ts +++ b/payload-types.ts @@ -67,6 +67,10 @@ export interface Config { }; blocks: {}; collections: { + tickets: Ticket; + revenue: Revenue; + events: Event; + 'payload-kv': PayloadKv; users: User; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -74,6 +78,10 @@ export interface Config { }; collectionsJoins: {}; collectionsSelect: { + tickets: TicketsSelect | TicketsSelect; + revenue: RevenueSelect | RevenueSelect; + events: EventsSelect | EventsSelect; + 'payload-kv': PayloadKvSelect | PayloadKvSelect; users: UsersSelect | UsersSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -82,9 +90,10 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: {}; globalsSelect: {}; - locale: 'en' | 'pl'; + locale: null; user: User & { collection: 'users'; }; @@ -111,14 +120,26 @@ export interface UserAuthOperations { password: string; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "tickets". + */ +export interface Ticket { + id: string; + title: string; + description?: string | null; + status: 'open' | 'in-progress' | 'closed'; + priority: 'low' | 'medium' | 'high' | 'critical'; + assignee?: (string | null) | User; + updatedAt: string; + createdAt: string; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". */ export interface User { id: string; - localizedField: string; - roles: ('admin' | 'editor' | 'moderator' | 'user' | 'viewer')[]; updatedAt: string; createdAt: string; email: string; @@ -128,18 +149,86 @@ export interface User { hash?: string | null; loginAttempts?: number | null; lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; password?: string | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "revenue". + */ +export interface Revenue { + id: string; + amount: number; + description: string; + date: string; + category: 'sales' | 'subscriptions' | 'services' | 'other'; + source?: string | null; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "events". + */ +export interface Event { + id: string; + title: string; + description?: string | null; + startDate: string; + endDate?: string | null; + location?: string | null; + type: 'meeting' | 'conference' | 'workshop' | 'webinar' | 'other'; + organizer?: (string | null) | User; + status: 'scheduled' | 'in-progress' | 'completed' | 'cancelled'; + updatedAt: string; + createdAt: string; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv". + */ +export interface PayloadKv { + id: string; + key: string; + data: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-locked-documents". */ export interface PayloadLockedDocument { id: string; - document?: { - relationTo: 'users'; - value: string | User; - } | null; + document?: + | ({ + relationTo: 'tickets'; + value: string | Ticket; + } | null) + | ({ + relationTo: 'revenue'; + value: string | Revenue; + } | null) + | ({ + relationTo: 'events'; + value: string | Event; + } | null) + | ({ + relationTo: 'users'; + value: string | User; + } | null); globalSlug?: string | null; user: { relationTo: 'users'; @@ -182,13 +271,61 @@ export interface PayloadMigration { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "tickets_select". + */ +export interface TicketsSelect { + title?: T; + description?: T; + status?: T; + priority?: T; + assignee?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "revenue_select". + */ +export interface RevenueSelect { + amount?: T; + description?: T; + date?: T; + category?: T; + source?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "events_select". + */ +export interface EventsSelect { + title?: T; + description?: T; + startDate?: T; + endDate?: T; + location?: T; + type?: T; + organizer?: T; + status?: T; + updatedAt?: T; + createdAt?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv_select". + */ +export interface PayloadKvSelect { + key?: T; + data?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". */ export interface UsersSelect { - localizedField?: T; - roles?: T; updatedAt?: T; createdAt?: T; email?: T; @@ -198,6 +335,13 @@ export interface UsersSelect { hash?: T; loginAttempts?: T; lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; } /** * This interface was referenced by `Config`'s JSON-Schema diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e732b84516c..67e2fb73941 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -707,7 +707,7 @@ importers: dependencies: ioredis: specifier: ^5.4.1 - version: 5.4.1 + version: 5.8.2 devDependencies: payload: specifier: workspace:* @@ -768,6 +768,12 @@ importers: '@dnd-kit/core': specifier: 6.0.8 version: 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/modifiers': + specifier: 9.0.0 + version: 9.0.0(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) + '@dnd-kit/sortable': + specifier: 7.0.2 + version: 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) '@payloadcms/graphql': specifier: workspace:* version: link:../graphql @@ -1197,13 +1203,13 @@ importers: dependencies: '@modelcontextprotocol/sdk': specifier: ^1.17.2 - version: 1.20.1 + version: 1.24.3(zod@3.25.76) '@types/json-schema': specifier: 7.0.15 version: 7.0.15 '@vercel/mcp-adapter': specifier: ^1.0.0 - version: 1.0.0(@modelcontextprotocol/sdk@1.20.1)(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.0.0(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) json-schema-to-zod: specifier: 2.6.1 version: 2.6.1 @@ -2318,6 +2324,10 @@ importers: version: 3.2.3(@types/debug@4.1.12)(@types/node@22.5.4)(jiti@2.5.1)(jsdom@26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1) test: + dependencies: + recharts: + specifier: 3.2.1 + version: 3.2.1(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react-is@18.3.1)(react@19.2.1)(redux@5.0.1) devDependencies: '@aws-sdk/client-s3': specifier: ^3.614.0 @@ -2336,7 +2346,7 @@ importers: version: 2.14.4 '@modelcontextprotocol/sdk': specifier: ^1.17.2 - version: 1.20.1 + version: 1.24.3(zod@3.25.76) '@next/env': specifier: 15.4.7 version: 15.4.7 @@ -4107,6 +4117,12 @@ packages: react: 19.2.1 react-dom: 19.2.1 + '@dnd-kit/modifiers@9.0.0': + resolution: {integrity: sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==} + peerDependencies: + '@dnd-kit/core': ^6.3.0 + react: 19.2.1 + '@dnd-kit/sortable@7.0.2': resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} peerDependencies: @@ -5310,8 +5326,8 @@ packages: cpu: [x64] os: [win32] - '@ioredis/commands@1.2.0': - resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} + '@ioredis/commands@1.4.0': + resolution: {integrity: sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -5596,9 +5612,15 @@ packages: engines: {node: '>=16.13'} deprecated: Miniflare v2 is no longer supported. Please upgrade to Miniflare v4 - '@modelcontextprotocol/sdk@1.20.1': - resolution: {integrity: sha512-j/P+yuxXfgxb+mW7OEoRCM3G47zCTDqUPivJo/VzpjbG8I9csTXtOprCf5FfOfHK4whOJny0aHuBEON+kS7CCA==} + '@modelcontextprotocol/sdk@1.24.3': + resolution: {integrity: sha512-YgSHW29fuzKKAHTGe9zjNoo+yF8KaQPzDC2W9Pv41E7/57IfY+AMGJ/aDFlgTLcVVELoggKE4syABCE75u3NCw==} engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true '@monaco-editor/loader@1.5.0': resolution: {integrity: sha512-hKoGSM+7aAc7eRTRjpqAZucPmoNOC4UUbknb/VNoTkEIkCPhqV8LfbsgM1webRM7S/z21eHEx9Fkwx8Z/C/+Xw==} @@ -6638,6 +6660,17 @@ packages: peerDependencies: '@redis/client': ^1.0.0 + '@reduxjs/toolkit@2.9.0': + resolution: {integrity: sha512-fSfQlSRu9Z5yBkvsNhYF2rPS8cGXn/TZVrlwN1948QyZ8xMZ0JvP50S2acZNaf+o63u6aEeMjipFyksjIcWrog==} + peerDependencies: + react: 19.2.1 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + '@rolldown/pluginutils@1.0.0-beta.11': resolution: {integrity: sha512-L/gAA/hyCSuzTF1ftlzUSI/IKr2POHsv1Dd78GfqkR83KMNuswWD61JxGV2L7nRwBBBSDr6R1gCkdTmoN7W4ag==} @@ -7709,6 +7742,12 @@ packages: '@speed-highlight/core@1.2.7': resolution: {integrity: sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==} + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + '@stripe/react-stripe-js@3.7.0': resolution: {integrity: sha512-PYls/2S9l0FF+2n0wHaEJsEU8x7CmBagiH7zYOsxbBlLIHEsqUIQ4MlIAbV9Zg6xwT8jlYdlRIyBTHmO3yM7kQ==} peerDependencies: @@ -7996,6 +8035,33 @@ packages: '@types/connect@3.4.36': resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==} + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-shape@3.1.7': + resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -8184,6 +8250,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + '@types/uuid@10.0.0': resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} @@ -8612,6 +8681,14 @@ packages: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv-keywords@3.5.2: resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} peerDependencies: @@ -9388,6 +9465,50 @@ packages: csv-stringify@6.5.2: resolution: {integrity: sha512-RFPahj0sXcmUyjrObAK+DOWtMvMIFV328n4qZJhgX3x2RqkQgOTU2mCUmiFR0CzM6AzChlRSUErjiJeEt8BaQA==} + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -9477,6 +9598,9 @@ packages: resolution: {integrity: sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + decimal.js-light@2.5.1: + resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} + decimal.js@10.5.0: resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} @@ -9895,6 +10019,9 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + es-toolkit@1.39.10: + resolution: {integrity: sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==} + esbuild-register@3.6.0: resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: @@ -10929,6 +11056,9 @@ packages: immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + immer@10.1.3: + resolution: {integrity: sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==} + immer@9.0.21: resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} @@ -10976,12 +11106,16 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + interpret@1.4.0: resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} - ioredis@5.4.1: - resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} + ioredis@5.8.2: + resolution: {integrity: sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==} engines: {node: '>=12.22.0'} ip-address@9.0.5: @@ -11452,6 +11586,9 @@ packages: jose@5.9.6: resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -11818,11 +11955,11 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - mcp-handler@1.0.3: - resolution: {integrity: sha512-AQ8I1a6wyfK0hIHeGqvjXqKHGvABDvw5dvwJvMjUiuKAUDgFsFtPExqThFOE/boOTbBKXn7fPSJ94soT0GjL+A==} + mcp-handler@1.0.4: + resolution: {integrity: sha512-bp5Xp6jKF8H3vh3Xadr83YZxHekKCXcbenTIej3DR0MK8GpQDMHNU/RDBvIRbs/7VRViPPkjMcWLsx+WYVICNw==} hasBin: true peerDependencies: - '@modelcontextprotocol/sdk': ^1.17.2 + '@modelcontextprotocol/sdk': ^1.22.0 next: '>=13.0.0' peerDependenciesMeta: next: @@ -12187,6 +12324,7 @@ packages: next@15.4.10: resolution: {integrity: sha512-itVlc79QjpKMFMRhP+kbGKaSG/gZM6RCvwhEbwmCNF06CdDiNaoHcbeg0PqkEa2GOcn8KJ0nnc7+yL7EjoYLHQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -12657,8 +12795,8 @@ packages: piscina@4.7.0: resolution: {integrity: sha512-b8hvkpp9zS0zsfa939b/jXbe64Z2gZv0Ha7FYPNUiDIB1y2AtxcOZdfP8xN8HFjUaqQiT9gRlfjAsoL8vdJ1Iw==} - pkce-challenge@5.0.0: - resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} engines: {node: '>=16.20.0'} pkg-dir@4.2.0: @@ -12990,6 +13128,18 @@ packages: react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-redux@9.2.0: + resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} + peerDependencies: + '@types/react': ^18.2.25 || ^19 + react: 19.2.1 + redux: ^5.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + redux: + optional: true + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} @@ -13073,6 +13223,14 @@ packages: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} + recharts@3.2.1: + resolution: {integrity: sha512-0JKwHRiFZdmLq/6nmilxEZl3pqb4T+aKkOkOi/ZISRZwfBhVMgInxzlYU9D4KnCH3KINScLy68m/OvMXoYGZUw==} + engines: {node: '>=18'} + peerDependencies: + react: 19.2.1 + react-dom: 19.2.1 + react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + rechoir@0.6.2: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} @@ -13088,6 +13246,14 @@ packages: redis@4.7.1: resolution: {integrity: sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==} + redux-thunk@3.1.0: + resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} + peerDependencies: + redux: ^5.0.0 + + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + refa@0.12.1: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -13157,6 +13323,9 @@ packages: resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} engines: {node: '>=0.10.5'} + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} @@ -14119,6 +14288,9 @@ packages: tiny-invariant@1.0.6: resolution: {integrity: sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==} + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tiny-warning@1.0.3: resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} @@ -14563,6 +14735,11 @@ packages: '@types/react': optional: true + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: 19.2.1 + utf-8-validate@6.0.5: resolution: {integrity: sha512-EYZR+OpIXp9Y1eG1iueg8KRsY8TuT8VNgnanZ0uA3STqhHQTLwbl+WX76/9X5OY12yQubymBpaBSmMPkSTQcKA==} engines: {node: '>=6.14.2'} @@ -14617,6 +14794,9 @@ packages: vfile-message@4.0.2: resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} + victory-vendor@37.3.6: + resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} + vite-node@3.2.3: resolution: {integrity: sha512-gc8aAifGuDIpZHrPjuHyP4dpQmYXqWw7D1GmDnWeNWP654UEXzVfQ5IHPSK5HaHkwB/+p1atpYpSdw/2kOv8iQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -14972,10 +15152,10 @@ packages: youch@4.1.0-beta.10: resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} - zod-to-json-schema@3.24.6: - resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} + zod-to-json-schema@3.25.0: + resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} peerDependencies: - zod: ^3.24.1 + zod: ^3.25 || ^4 zod-validation-error@3.4.0: resolution: {integrity: sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==} @@ -17732,6 +17912,13 @@ snapshots: react-dom: 19.2.1(react@19.2.1) tslib: 2.8.1 + '@dnd-kit/modifiers@9.0.0(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': + dependencies: + '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/utilities': 3.2.2(react@19.2.1) + react: 19.2.1 + tslib: 2.8.1 + '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': dependencies: '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -18640,7 +18827,7 @@ snapshots: '@img/sharp-wasm32@0.34.3': dependencies: - '@emnapi/runtime': 1.7.1 + '@emnapi/runtime': 1.4.5 optional: true '@img/sharp-win32-arm64@0.34.2': @@ -18667,7 +18854,7 @@ snapshots: '@img/sharp-win32-x64@0.34.3': optional: true - '@ioredis/commands@1.2.0': {} + '@ioredis/commands@1.4.0': {} '@isaacs/cliui@8.0.2': dependencies: @@ -19151,9 +19338,10 @@ snapshots: dependencies: '@miniflare/shared': 2.14.4 - '@modelcontextprotocol/sdk@1.20.1': + '@modelcontextprotocol/sdk@1.24.3(zod@3.25.76)': dependencies: - ajv: 6.12.6 + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) content-type: 1.0.5 cors: 2.8.5 cross-spawn: 7.0.6 @@ -19161,10 +19349,11 @@ snapshots: eventsource-parser: 3.0.6 express: 5.0.1 express-rate-limit: 7.5.1(express@5.0.1) - pkce-challenge: 5.0.0 + jose: 6.1.3 + pkce-challenge: 5.0.1 raw-body: 3.0.1 zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) + zod-to-json-schema: 3.25.0(zod@3.25.76) transitivePeerDependencies: - supports-color @@ -20162,6 +20351,18 @@ snapshots: dependencies: '@redis/client': 1.6.1 + '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.2.1)(react@19.2.1)(redux@5.0.1))(react@19.2.1)': + dependencies: + '@standard-schema/spec': 1.0.0 + '@standard-schema/utils': 0.3.0 + immer: 10.1.3 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.1.1 + optionalDependencies: + react: 19.2.1 + react-redux: 9.2.0(@types/react@19.2.1)(react@19.2.1)(redux@5.0.1) + '@rolldown/pluginutils@1.0.0-beta.11': {} '@rollup/plugin-commonjs@26.0.1(rollup@3.29.5)': @@ -21674,6 +21875,10 @@ snapshots: '@speed-highlight/core@1.2.7': {} + '@standard-schema/spec@1.0.0': {} + + '@standard-schema/utils@0.3.0': {} + '@stripe/react-stripe-js@3.7.0(@stripe/stripe-js@4.10.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: '@stripe/stripe-js': 4.10.0 @@ -21968,6 +22173,30 @@ snapshots: dependencies: '@types/node': 22.15.30 + '@types/d3-array@3.2.2': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-shape@3.1.7': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + '@types/debug@4.1.12': dependencies: '@types/ms': 0.7.34 @@ -22191,6 +22420,8 @@ snapshots: '@types/unist@3.0.3': {} + '@types/use-sync-external-store@0.0.6': {} + '@types/uuid@10.0.0': {} '@types/webidl-conversions@7.0.3': {} @@ -22400,10 +22631,10 @@ snapshots: '@vercel/git-hooks@1.0.0': {} - '@vercel/mcp-adapter@1.0.0(@modelcontextprotocol/sdk@1.20.1)(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))': + '@vercel/mcp-adapter@1.0.0(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))': dependencies: - '@modelcontextprotocol/sdk': 1.20.1 - mcp-handler: 1.0.3(@modelcontextprotocol/sdk@1.20.1)(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + '@modelcontextprotocol/sdk': 1.24.3(zod@3.25.76) + mcp-handler: 1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) optionalDependencies: next: 15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) @@ -22742,6 +22973,10 @@ snapshots: clean-stack: 2.2.0 indent-string: 4.0.0 + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + ajv-keywords@3.5.2(ajv@6.12.6): dependencies: ajv: 6.12.6 @@ -23604,6 +23839,44 @@ snapshots: csv-stringify@6.5.2: {} + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-color@3.1.0: {} + + d3-ease@3.0.1: {} + + d3-format@3.1.0: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@3.1.0: {} + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + damerau-levenshtein@1.0.8: {} data-uri-to-buffer@4.0.1: {} @@ -23677,6 +23950,8 @@ snapshots: debuglog@1.0.1: {} + decimal.js-light@2.5.1: {} + decimal.js@10.5.0: {} decode-named-character-reference@1.0.2: @@ -24106,6 +24381,8 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + es-toolkit@1.39.10: {} + esbuild-register@3.6.0(esbuild@0.25.5): dependencies: debug: 4.4.1 @@ -25479,6 +25756,8 @@ snapshots: immediate@3.0.6: {} + immer@10.1.3: {} + immer@9.0.21: {} immutable@4.3.7: {} @@ -25529,13 +25808,15 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + internmap@2.0.3: {} + interpret@1.4.0: {} - ioredis@5.4.1: + ioredis@5.8.2: dependencies: - '@ioredis/commands': 1.2.0 + '@ioredis/commands': 1.4.0 cluster-key-slot: 1.1.2 - debug: 4.3.7 + debug: 4.4.1 denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -26183,6 +26464,8 @@ snapshots: jose@5.9.6: {} + jose@6.1.3: {} + joycon@3.1.1: {} js-base64@3.7.7: {} @@ -26555,9 +26838,9 @@ snapshots: math-intrinsics@1.1.0: {} - mcp-handler@1.0.3(@modelcontextprotocol/sdk@1.20.1)(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + mcp-handler@1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: - '@modelcontextprotocol/sdk': 1.20.1 + '@modelcontextprotocol/sdk': 1.24.3(zod@3.25.76) chalk: 5.3.0 commander: 11.1.0 redis: 4.7.1 @@ -26792,7 +27075,7 @@ snapshots: micromark@4.0.1: dependencies: '@types/debug': 4.1.12 - debug: 4.3.7 + debug: 4.4.1 decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.2 @@ -26998,7 +27281,7 @@ snapshots: mquery@5.0.0: dependencies: - debug: 4.4.1 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -27602,7 +27885,7 @@ snapshots: optionalDependencies: '@napi-rs/nice': 1.0.1 - pkce-challenge@5.0.0: {} + pkce-challenge@5.0.1: {} pkg-dir@4.2.0: dependencies: @@ -27858,6 +28141,15 @@ snapshots: react-is@18.3.1: {} + react-redux@9.2.0(@types/react@19.2.1)(react@19.2.1)(redux@5.0.1): + dependencies: + '@types/use-sync-external-store': 0.0.6 + react: 19.2.1 + use-sync-external-store: 1.5.0(react@19.2.1) + optionalDependencies: + '@types/react': 19.2.1 + redux: 5.0.1 + react-refresh@0.17.0: {} react-remove-scroll-bar@2.3.8(@types/react@19.2.1)(react@19.2.1): @@ -27973,6 +28265,26 @@ snapshots: real-require@0.2.0: {} + recharts@3.2.1(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react-is@18.3.1)(react@19.2.1)(redux@5.0.1): + dependencies: + '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.2.1)(react@19.2.1)(redux@5.0.1))(react@19.2.1) + clsx: 2.1.1 + decimal.js-light: 2.5.1 + es-toolkit: 1.39.10 + eventemitter3: 5.0.1 + immer: 10.1.3 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + react-is: 18.3.1 + react-redux: 9.2.0(@types/react@19.2.1)(react@19.2.1)(redux@5.0.1) + reselect: 5.1.1 + tiny-invariant: 1.3.3 + use-sync-external-store: 1.5.0(react@19.2.1) + victory-vendor: 37.3.6 + transitivePeerDependencies: + - '@types/react' + - redux + rechoir@0.6.2: dependencies: resolve: 1.22.8 @@ -27992,6 +28304,12 @@ snapshots: '@redis/search': 1.2.0(@redis/client@1.6.1) '@redis/time-series': 1.1.0(@redis/client@1.6.1) + redux-thunk@3.1.0(redux@5.0.1): + dependencies: + redux: 5.0.1 + + redux@5.0.1: {} + refa@0.12.1: dependencies: '@eslint-community/regexpp': 4.12.1 @@ -28080,6 +28398,8 @@ snapshots: requireindex@1.2.0: {} + reselect@5.1.1: {} + resolve-alpn@1.2.1: {} resolve-cwd@3.0.0: @@ -29256,6 +29576,8 @@ snapshots: tiny-invariant@1.0.6: {} + tiny-invariant@1.3.3: {} + tiny-warning@1.0.3: {} tinybench@2.9.0: {} @@ -29699,6 +30021,10 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 + use-sync-external-store@1.5.0(react@19.2.1): + dependencies: + react: 19.2.1 + utf-8-validate@6.0.5: dependencies: node-gyp-build: 4.8.2 @@ -29743,6 +30069,23 @@ snapshots: '@types/unist': 3.0.3 unist-util-stringify-position: 4.0.0 + victory-vendor@37.3.6: + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-ease': 3.0.2 + '@types/d3-interpolate': 3.0.4 + '@types/d3-scale': 4.0.9 + '@types/d3-shape': 3.1.7 + '@types/d3-time': 3.0.4 + '@types/d3-timer': 3.0.2 + d3-array: 3.2.4 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-timer: 3.0.1 + vite-node@3.2.3(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: cac: 6.7.14 @@ -30258,7 +30601,7 @@ snapshots: cookie: 1.0.2 youch-core: 0.3.3 - zod-to-json-schema@3.24.6(zod@3.25.76): + zod-to-json-schema@3.25.0(zod@3.25.76): dependencies: zod: 3.25.76 diff --git a/test/admin/e2e/general/e2e.spec.ts b/test/admin/e2e/general/e2e.spec.ts index 99243236285..1fe2b800dd7 100644 --- a/test/admin/e2e/general/e2e.spec.ts +++ b/test/admin/e2e/general/e2e.spec.ts @@ -434,9 +434,12 @@ describe('General', () => { test('dashboard — should navigate to collection', async () => { await page.goto(postsUrl.admin) - const anchor = page.locator(`#card-${postsCollectionSlug} a.card__click`) + const anchor = page.locator(`.card-${postsCollectionSlug} a.card__click`) const anchorHref = await anchor.getAttribute('href') await anchor.click() + // flaky + // eslint-disable-next-line playwright/no-wait-for-timeout + await page.waitForTimeout(1000) await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).toContain(anchorHref) }) @@ -567,7 +570,10 @@ describe('General', () => { test('should replace history when adding query params to the URL and not push a new entry', async () => { await page.goto(postsUrl.admin) - await page.locator('.dashboard__card-list .card').first().click() + await page.locator('.collections__card-list .card__click').first().click() + // flaky + // eslint-disable-next-line playwright/no-wait-for-timeout + await page.waitForTimeout(1000) // wait for the search params to get injected into the URL const escapedAdminURL = postsUrl.admin.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') const pattern = new RegExp(`${escapedAdminURL}/collections/[^?]+\\?limit=[^&]+`) @@ -960,7 +966,7 @@ describe('General', () => { describe('progress bar', () => { test('should show progress bar on page navigation', async () => { await page.goto(postsUrl.admin) - await page.locator('.dashboard__card-list .card').first().click() + await page.locator('.collections__card-list .card').first().click() await expect(page.locator('.progress-bar')).toBeVisible() }) }) diff --git a/test/dashboard/collections/Events.ts b/test/dashboard/collections/Events.ts new file mode 100644 index 00000000000..036c5b58de5 --- /dev/null +++ b/test/dashboard/collections/Events.ts @@ -0,0 +1,90 @@ +import type { CollectionConfig } from 'payload' + +export const Events: CollectionConfig = { + slug: 'events', + admin: { + group: 'Dashboard Data', + useAsTitle: 'title', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'description', + type: 'textarea', + }, + { + name: 'startDate', + type: 'date', + required: true, + }, + { + name: 'endDate', + type: 'date', + }, + { + name: 'location', + type: 'text', + }, + { + name: 'type', + type: 'select', + required: true, + defaultValue: 'meeting', + options: [ + { + label: 'Meeting', + value: 'meeting', + }, + { + label: 'Conference', + value: 'conference', + }, + { + label: 'Workshop', + value: 'workshop', + }, + { + label: 'Webinar', + value: 'webinar', + }, + { + label: 'Other', + value: 'other', + }, + ], + }, + { + name: 'organizer', + type: 'relationship', + relationTo: 'users', + }, + { + name: 'status', + type: 'select', + required: true, + defaultValue: 'scheduled', + options: [ + { + label: 'Scheduled', + value: 'scheduled', + }, + { + label: 'In Progress', + value: 'in-progress', + }, + { + label: 'Completed', + value: 'completed', + }, + { + label: 'Cancelled', + value: 'cancelled', + }, + ], + }, + ], +} diff --git a/test/dashboard/collections/Revenue.ts b/test/dashboard/collections/Revenue.ts new file mode 100644 index 00000000000..c03bcfd9656 --- /dev/null +++ b/test/dashboard/collections/Revenue.ts @@ -0,0 +1,56 @@ +import type { CollectionConfig } from 'payload' + +export const Revenue: CollectionConfig = { + slug: 'revenue', + admin: { + group: 'Dashboard Data', + useAsTitle: 'description', + }, + fields: [ + { + name: 'amount', + type: 'number', + required: true, + min: 0, + }, + { + name: 'description', + type: 'text', + required: true, + }, + { + name: 'date', + type: 'date', + required: true, + defaultValue: () => new Date().toISOString(), + }, + { + name: 'category', + type: 'select', + required: true, + defaultValue: 'sales', + options: [ + { + label: 'Sales', + value: 'sales', + }, + { + label: 'Subscriptions', + value: 'subscriptions', + }, + { + label: 'Services', + value: 'services', + }, + { + label: 'Other', + value: 'other', + }, + ], + }, + { + name: 'source', + type: 'text', + }, + ], +} diff --git a/test/dashboard/collections/Tickets.ts b/test/dashboard/collections/Tickets.ts new file mode 100644 index 00000000000..394193dbe3d --- /dev/null +++ b/test/dashboard/collections/Tickets.ts @@ -0,0 +1,69 @@ +import type { CollectionConfig } from 'payload' + +export const Tickets: CollectionConfig = { + slug: 'tickets', + admin: { + group: 'Dashboard Data', + useAsTitle: 'title', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'description', + type: 'textarea', + }, + { + name: 'status', + type: 'select', + required: true, + defaultValue: 'open', + options: [ + { + label: 'Open', + value: 'open', + }, + { + label: 'In Progress', + value: 'in-progress', + }, + { + label: 'Closed', + value: 'closed', + }, + ], + }, + { + name: 'priority', + type: 'select', + required: true, + defaultValue: 'medium', + options: [ + { + label: 'Low', + value: 'low', + }, + { + label: 'Medium', + value: 'medium', + }, + { + label: 'High', + value: 'high', + }, + { + label: 'Critical', + value: 'critical', + }, + ], + }, + { + name: 'assignee', + type: 'relationship', + relationTo: 'users', + }, + ], +} diff --git a/test/dashboard/components/BeforeOrAfterDashboard.tsx b/test/dashboard/components/BeforeOrAfterDashboard.tsx new file mode 100644 index 00000000000..7184ee0f535 --- /dev/null +++ b/test/dashboard/components/BeforeOrAfterDashboard.tsx @@ -0,0 +1,8 @@ +/* eslint-disable no-restricted-exports */ +export default function BeforeOrAfterDashboard() { + return ( +
+

Before or After Dashboard

+
+ ) +} diff --git a/test/dashboard/components/Count.tsx b/test/dashboard/components/Count.tsx new file mode 100644 index 00000000000..82a73d1788f --- /dev/null +++ b/test/dashboard/components/Count.tsx @@ -0,0 +1,116 @@ +/* eslint-disable no-restricted-exports */ +import { type WidgetServerProps } from 'payload' + +export default async function Count({ req }: WidgetServerProps) { + let count = 0 + let error: null | string = null + + // TODO: Dynamic collection counting using fields + const collection = 'tickets' + const payload = req.payload + const title = 'Tickets' + const color = 'blue' + const icon = '📊' + const changePercent = 10 + const changeText = '10% increase' + + try { + const result = await payload.count({ + // @ts-expect-error - Dynamic collection counting + collection, + }) + count = result.totalDocs + } catch (err) { + error = err instanceof Error ? err.message : 'Failed to fetch count' + // eslint-disable-next-line no-console + console.error(`Error fetching count for ${collection}:`, err) + } + + const getColorStyles = (color: 'blue' | 'green' | 'orange' | 'purple' | 'red') => { + const colors = { + blue: { backgroundColor: '#eff6ff', color: '#2563eb' }, + green: { backgroundColor: '#ecfdf5', color: '#059669' }, + orange: { backgroundColor: '#fff7ed', color: '#ea580c' }, + purple: { backgroundColor: '#faf5ff', color: '#9333ea' }, + red: { backgroundColor: '#fef2f2', color: '#dc2626' }, + } + return colors[color] + } + + return ( +
+ {error ? ( +
+
+ + ⚠️ + +
+

{title}

+

+ {error} +

+
+ ) : ( + <> +
+
+ + {icon} + +
+

{title}

+
+ +
+ {count.toLocaleString()} +
+ + {changePercent !== undefined && changeText && ( +
+ 0 ? '#059669' : changePercent < 0 ? '#dc2626' : '#6b7280', + fontSize: '14px', + fontWeight: 600, + }} + > + {changePercent > 0 ? '+' : ''} + {changePercent}% + + {changeText} +
+ )} + + )} +
+ ) +} diff --git a/test/dashboard/components/Private.tsx b/test/dashboard/components/Private.tsx new file mode 100644 index 00000000000..71118de5a09 --- /dev/null +++ b/test/dashboard/components/Private.tsx @@ -0,0 +1,73 @@ +/* eslint-disable no-restricted-exports */ +'use client' + +import type { WidgetServerProps } from 'payload' + +export default function Private({ widgetSlug }: WidgetServerProps) { + return ( +
+
+

Private Widget

+
+ ADMIN ONLY +
+
+ +
+
+ + 🔒 + {' '} + This is a private widget only visible to admin users +
+
+ Widget ID: {widgetSlug} +
+
+
+ ) +} diff --git a/test/dashboard/components/Revenue.tsx b/test/dashboard/components/Revenue.tsx new file mode 100644 index 00000000000..a100b9c7d09 --- /dev/null +++ b/test/dashboard/components/Revenue.tsx @@ -0,0 +1,156 @@ +/* eslint-disable no-restricted-exports */ +'use client' + +import { type WidgetServerProps } from 'payload' +import { Area, AreaChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts' + +interface RevenueData { + amount: number + date: string + period: string +} + +export default function Revenue(_props: WidgetServerProps) { + const timeframe = 'monthly' + const title = 'Revenue Statistics' + // Mock data for now - in real implementation, this would come from props or server-side fetch + const mockData: RevenueData[] = [ + { amount: 20000, date: '2024-01', period: 'Jan' }, + { amount: 25000, date: '2024-02', period: 'Feb' }, + { amount: 18000, date: '2024-03', period: 'Mar' }, + { amount: 30000, date: '2024-04', period: 'Apr' }, + { amount: 35000, date: '2024-05', period: 'May' }, + { amount: 28000, date: '2024-06', period: 'Jun' }, + { amount: 40000, date: '2024-07', period: 'Jul' }, + { amount: 38000, date: '2024-08', period: 'Aug' }, + { amount: 45000, date: '2024-09', period: 'Sep' }, + { amount: 42000, date: '2024-10', period: 'Oct' }, + { amount: 48000, date: '2024-11', period: 'Nov' }, + { amount: 52000, date: '2024-12', period: 'Dec' }, + ] + + const formatCurrency = (value: number) => { + return new Intl.NumberFormat('en-US', { + currency: 'USD', + minimumFractionDigits: 0, + style: 'currency', + }).format(value) + } + + function CustomTooltip(props: { + active?: boolean + label?: number | string + payload?: { value: number }[] + }) { + const { active, label, payload } = props + if (active && payload && payload.length) { + return ( +
+

+ {label} +

+

+ {formatCurrency(payload[0]?.value ?? 0)} +

+
+ ) + } + return null + } + + return ( +
+
+

{title}

+
+ +
+
+ +
+ + + + + + + + + + `$${value / 1000}k`} + tickLine={false} + /> + } /> + + + +
+
+ ) +} diff --git a/test/dashboard/config.ts b/test/dashboard/config.ts new file mode 100644 index 00000000000..a25a63181e9 --- /dev/null +++ b/test/dashboard/config.ts @@ -0,0 +1,96 @@ +import { fileURLToPath } from 'node:url' +import path from 'path' +import { type WidgetInstance } from 'payload' + +import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' +import { Events } from './collections/Events.js' +import { Revenue } from './collections/Revenue.js' +import { Tickets } from './collections/Tickets.js' +import { seed } from './seed.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +export default buildConfigWithDefaults({ + admin: { + importMap: { + baseDir: path.resolve(dirname), + }, + components: { + afterDashboard: ['./components/BeforeOrAfterDashboard.js'], + beforeDashboard: ['./components/BeforeOrAfterDashboard.js'], + // views: { + // dashboard: { + // Component: { + // path: './components/Revenue.tsx#default', + // }, + // }, + // }, + }, + dashboard: { + defaultLayout: ({ req: { user } }) => { + const baseWidgets: WidgetInstance[] = [ + { + widgetSlug: 'collections', + width: 'full', + }, + ...Array.from( + { length: 4 }, + (): WidgetInstance => ({ + widgetSlug: 'count', + width: 'x-small', + }), + ), + { + widgetSlug: 'revenue', + width: 'full', + }, + ] + + if (user?.email === 'dev@payloadcms.com') { + baseWidgets.push({ + widgetSlug: 'private', + width: 'full', + }) + } + return baseWidgets + }, + widgets: [ + { + slug: 'count', + ComponentPath: './components/Count.tsx#default', + label: { + en: 'Count Widget', + es: 'Widget de Conteo', + }, + maxWidth: 'medium', + // fields: [] + }, + { + slug: 'private', + ComponentPath: './components/Private.tsx#default', + label: 'Private Widget', + }, + { + slug: 'revenue', + ComponentPath: './components/Revenue.tsx#default', + // Demonstrates function form with i18n - returns localized label via t() + label: ({ i18n }) => (i18n.language === 'es' ? 'Gráfico de Ingresos' : 'Revenue Chart'), + minWidth: 'medium', + }, + ], + }, + }, + collections: [ + Tickets, + Revenue, + Events, + // ...Array.from({ length: 35 }, () => ({ + // slug: `collection-${Math.random().toString(36).substring(2, 15)}`, + // fields: [], + // })), + ], + onInit: async (payload) => { + await seed(payload) + }, +}) diff --git a/test/dashboard/e2e.spec.ts b/test/dashboard/e2e.spec.ts new file mode 100644 index 00000000000..36e169dc3d7 --- /dev/null +++ b/test/dashboard/e2e.spec.ts @@ -0,0 +1,202 @@ +/* eslint-disable playwright/expect-expect */ +import { expect, test } from '@playwright/test' +import path from 'path' +import { fileURLToPath } from 'url' + +import { ensureCompilationIsDone } from '../helpers.js' +import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' +import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' +import { reInitializeDB } from '../helpers/reInitializeDB.js' +import { TEST_TIMEOUT_LONG } from '../playwright.config.js' +import { DashboardHelper } from './utils.js' + +const filename = fileURLToPath(import.meta.url) +const currentFolder = path.dirname(filename) +const dirname = path.resolve(currentFolder, '../../') + +const { beforeAll, beforeEach, describe } = test + +const { serverURL } = await initPayloadE2ENoConfig({ + dirname, +}) + +const url = new AdminUrlUtil(serverURL, 'users') + +describe('Dashboard', () => { + beforeAll(async ({ browser }, testInfo) => { + testInfo.setTimeout(TEST_TIMEOUT_LONG) + process.env.SEED_IN_CONFIG_ONINIT = 'false' // Makes it so the payload config onInit seed is not run. Otherwise, the seed would be run unnecessarily twice for the initial test run - once for beforeEach and once for onInit + const page = await browser.newPage() + await ensureCompilationIsDone({ page, serverURL }) + await page.close() + }) + beforeEach(async ({ page }) => { + await reInitializeDB({ + serverURL, + snapshotKey: 'lexicalTest', + uploadsDir: [path.resolve(dirname, './collections/Upload/uploads')], + }) + await page.goto(url.admin) + }) + + test('initial dashboard', async ({ page }) => { + const d = new DashboardHelper(page) + await expect(d.widgets).toHaveCount(7) + + await d.assertIsEditing(false) + await d.assertWidget(1, 'collections', 'full') + await d.assertWidget(2, 'count', 'x-small') + await d.assertWidget(3, 'count', 'x-small') + await d.assertWidget(4, 'count', 'x-small') + await d.assertWidget(5, 'count', 'x-small') + await d.assertWidget(6, 'revenue', 'full') + await d.assertWidget(7, 'private', 'full') + await d.validateLayout() + }) + + test('respects min and max width', async ({ page }) => { + const d = new DashboardHelper(page) + await d.setEditing() + await d.assertWidthRange({ position: 1, min: 'full', max: 'full' }) + await d.assertWidthRange({ position: 2, min: 'x-small', max: 'medium' }) + await d.assertWidthRange({ position: 3, min: 'x-small', max: 'medium' }) + await d.assertWidthRange({ position: 4, min: 'x-small', max: 'medium' }) + await d.assertWidthRange({ position: 5, min: 'x-small', max: 'medium' }) + await d.assertWidthRange({ position: 6, min: 'medium', max: 'full' }) + await d.assertWidthRange({ position: 7, min: 'x-small', max: 'full' }) + }) + + test('resize widget', async ({ page }) => { + const d = new DashboardHelper(page) + await d.setEditing() + await d.assertWidget(2, 'count', 'x-small') + await d.resizeWidget(2, 'medium') + await d.assertWidget(2, 'count', 'medium') + await d.saveChangesAndValidate() + }) + + test('add widget', async ({ page }) => { + const d = new DashboardHelper(page) + await d.setEditing() + await d.addWidget('revenue') + await d.assertWidget(8, 'revenue', 'medium') + await d.saveChangesAndValidate() + }) + + test('delete widget', async ({ page }) => { + const d = new DashboardHelper(page) + await d.setEditing() + await d.deleteWidget(1) + await d.assertWidget(1, 'count', 'x-small') + await d.assertWidget(6, 'private', 'full') + await expect(d.widgets).toHaveCount(6) + await d.saveChangesAndValidate() + }) + + test('empty dashboard - delete all widgets', async ({ page }) => { + const d = new DashboardHelper(page) + await d.setEditing() + await d.deleteWidget(1) + await d.deleteWidget(1) + await d.deleteWidget(1) + await d.deleteWidget(1) + await d.deleteWidget(1) + await d.deleteWidget(1) + await d.deleteWidget(1) + await expect(d.widgets).toHaveCount(0) + await expect(page.getByText('There are no widgets on your dashboard')).toBeVisible() + await d.saveChangesAndValidate() + }) + + test('Widgets should expand to the height of the tallest widget in the row', async ({ page }) => { + // For this test we need to put 2 widgets with different default heights in the same row + const d = new DashboardHelper(page) + await d.setEditing() + await d.deleteWidget(2) + await d.deleteWidget(2) + await d.resizeWidget(4, 'medium') + // validateLayout already takes care of verifying that + await d.saveChangesAndValidate() + }) + + test('cancel editing', async ({ page }) => { + const d = new DashboardHelper(page) + await d.setEditing() + await d.addWidget('revenue') + await d.cancelEditing() + await expect(d.widgets).toHaveCount(7) + await d.validateLayout() + }) + + test('reset layout', async ({ page }) => { + const d = new DashboardHelper(page) + await d.setEditing() + await d.addWidget('revenue') + await d.saveChangesAndValidate() + await d.resetLayout() + await expect(d.widgets).toHaveCount(7) + await d.validateLayout() + }) + + test('move widgets', async ({ page }) => { + const d = new DashboardHelper(page) + await d.setEditing() + // moveWidget already contains validations + await d.moveWidget(2, 1) // to first position + await d.moveWidget(1, 2, 'after') // after last in row + await d.moveWidget(2, 7, 'after') // to last position + await d.moveWidget(3, 6, 'before') // before first in row + await d.saveChangesAndValidate() + }) + + test('cannot move or edit widgets when not editing', async ({ page }) => { + const d = new DashboardHelper(page) + await d.assertIsEditing(false) + + // Delete buttons should not be visible when not editing + const widget = d.widgetByPos(1) + await widget.hover() + await expect(widget.getByText('Delete widget')).toBeHidden() + + // Widgets should not have draggable attributes when not editing + await expect(widget.locator('.draggable')).not.toHaveAttribute('aria-disabled') + + // verify the opposite: + await d.setEditing() + await expect(widget.getByText('Delete widget')).toBeVisible() + await expect(widget.locator('.draggable')).toHaveAttribute('aria-disabled', 'false') + }) + + test('Responsiveness - all widgets have a 100% width on mobile', async ({ page }) => { + // Set viewport to mobile size + await page.setViewportSize({ width: 500, height: 667 }) + const d = new DashboardHelper(page) + const widgets = await d.widgets.all() + for (const widget of widgets) { + await expect(async () => { + const dashboardBox = (await d.dashboard.boundingBox())! + const widgetBox = (await widget.boundingBox())! + expect(widgetBox.width).toBe(dashboardBox.width) + }).toPass({ timeout: 1000 }) + } + }) + + // TODO: reorder widgets with keyboard (for a11y reasons) + // It's already working. But I'd like to test it properly with a screen reader and everything. + + test('widget labels are displayed correctly in the add widget drawer', async ({ page }) => { + const d = new DashboardHelper(page) + await d.setEditing() + await d.openAddWidgetDrawer() + + // Verify custom labels are displayed (English) + await expect(async () => { + const labels = await d.getWidgetLabelsInDrawer() + expect(labels).toContain('Count Widget') + expect(labels).toContain('Private Widget') + expect(labels).toContain('Revenue Chart') + // The default 'collections' widget should use toWords fallback + expect(labels).toContain('Collections') + }).toPass({ timeout: 1000 }) + }) +}) diff --git a/test/dashboard/seed.ts b/test/dashboard/seed.ts new file mode 100644 index 00000000000..da2fefd0bb6 --- /dev/null +++ b/test/dashboard/seed.ts @@ -0,0 +1,73 @@ +import type { BasePayload } from 'payload' + +import { devUser } from '../credentials.js' + +export const seed = async (payload: BasePayload) => { + await payload.create({ + collection: 'users', + data: { + email: devUser.email, + password: devUser.password, + }, + }) + + // Create some sample data + try { + // Create sample tickets + for (let i = 1; i <= 35; i++) { + await payload.create({ + collection: 'tickets', + data: { + title: `Support Ticket #${i}`, + description: `Sample ticket description for ticket ${i}`, + status: ['open', 'in-progress', 'closed'][Math.floor(Math.random() * 3)], + priority: ['low', 'medium', 'high', 'critical'][Math.floor(Math.random() * 4)], + }, + }) + } + + // Create sample revenue entries + const months = ['2024-01', '2024-02', '2024-03', '2024-04', '2024-05', '2024-06'] + for (const month of months) { + for (let i = 1; i <= Math.floor(Math.random() * 10) + 5; i++) { + await payload.create({ + collection: 'revenue', + data: { + amount: Math.floor(Math.random() * 10000) + 1000, + description: `Revenue entry ${i} for ${month}`, + date: `${month}-${String(Math.floor(Math.random() * 28) + 1).padStart(2, '0')}`, + category: ['sales', 'subscriptions', 'services', 'other'][ + Math.floor(Math.random() * 4) + ], + source: 'Sample data', + }, + }) + } + } + + // Create sample events + const currentDate = new Date() + for (let i = 1; i <= 550; i++) { + const eventDate = new Date(currentDate) + eventDate.setDate(currentDate.getDate() + Math.floor(Math.random() * 365) - 180) // Random date within ±6 months + + await payload.create({ + collection: 'events', + data: { + title: `Event ${i}`, + description: `Sample event description for event ${i}`, + startDate: eventDate.toISOString(), + type: ['meeting', 'conference', 'workshop', 'webinar', 'other'][ + Math.floor(Math.random() * 5) + ], + status: ['scheduled', 'in-progress', 'completed', 'cancelled'][ + Math.floor(Math.random() * 4) + ], + location: `Location ${i}`, + }, + }) + } + } catch (err) { + console.error('Error creating sample data:', err) + } +} diff --git a/test/dashboard/tsconfig.eslint.json b/test/dashboard/tsconfig.eslint.json new file mode 100644 index 00000000000..b34cc7afbb8 --- /dev/null +++ b/test/dashboard/tsconfig.eslint.json @@ -0,0 +1,13 @@ +{ + // extend your base config to share compilerOptions, etc + //"extends": "./tsconfig.json", + "compilerOptions": { + // ensure that nobody can accidentally use this config for a build + "noEmit": true + }, + "include": [ + // whatever paths you intend to lint + "./**/*.ts", + "./**/*.tsx" + ] +} diff --git a/test/dashboard/tsconfig.json b/test/dashboard/tsconfig.json new file mode 100644 index 00000000000..3c43903cfdd --- /dev/null +++ b/test/dashboard/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.json" +} diff --git a/test/dashboard/utils.ts b/test/dashboard/utils.ts new file mode 100644 index 00000000000..18bba77996e --- /dev/null +++ b/test/dashboard/utils.ts @@ -0,0 +1,289 @@ +/* eslint-disable perfectionist/sort-classes */ + +import type { WidgetWidth } from 'payload' + +import { expect, type Page } from '@playwright/test' + +export class DashboardHelper { + private page: Page + + constructor(page: Page) { + this.page = page + } + + get dashboard() { + return this.page.locator('.modular-dashboard') + } + + get widgets() { + return this.page.locator('.widget') + } + + get stepNavLast() { + return this.page.locator('.step-nav__last') + } + + widgetByPos = (pos: number) => this.page.locator(`.modular-dashboard > :nth-child(${pos})`) + + getSnapshot = async (): Promise<[slug: string, width: WidgetWidth][]> => { + const widgets: [slug: string, width: WidgetWidth][] = await Promise.all( + (await this.widgets.all()).map(async (widget) => [ + (await widget.getAttribute('data-slug'))!, + (await widget.getAttribute('data-width')) as WidgetWidth, + ]), + ) + return widgets + } + + /** + * - Verify that flex wrap is working correctly (If a node exceeds 100% of the available width, it should go in the row below) + * - Verify that the nodes are positioned without gaps or overlap + * - Verify that all nodes in a row have the same height + */ + validateLayout = async () => { + const WIDTH_TO_COLS = { + 'x-small': 3, + small: 4, + medium: 6, + large: 8, + 'x-large': 9, + full: 12, + } + const widgets = await this.widgets.all() + let currentPos = 0 + for (let index = 0; index < widgets.length; index++) { + const widget = widgets[index]! + const width = await widget.getAttribute('data-width') + if (!width) { + throw new Error(`Widget has no width`) + } + const cols = WIDTH_TO_COLS[width as WidgetWidth] + const dashboardBox = await this.dashboard.boundingBox() + const widgetBox = await widget.boundingBox() + if (!widgetBox || !dashboardBox) { + throw new Error('Widget or dashboard box not found') + } + + // Determine expected position + let expectedX: number + if (currentPos === 0 || currentPos + cols > 12) { + // Widget is at the start of a new row + expectedX = dashboardBox.x + } else { + // Widget continues on the same row + const previousWidgetBox = (await widgets[index - 1]!.boundingBox())! + expectedX = previousWidgetBox.x + previousWidgetBox.width + expect(widgetBox.y + widgetBox.height).toBe(previousWidgetBox.y + previousWidgetBox.height) + const innerWidgetBox = (await widget.locator('.draggable').boundingBox())! + expect(innerWidgetBox.y + innerWidgetBox.height).toBe(widgetBox.y + widgetBox.height - 6) // 6px padding + } + + expect(widgetBox.x).toBe(expectedX) + + // Update currentPos, wrapping to new row if needed + currentPos += cols + if (currentPos >= 12) { + expect(widgetBox.x + widgetBox.width).toBe(dashboardBox.x + dashboardBox.width) + currentPos = 0 + } + } + } + + resizeWidget = async (position: number, width: WidgetWidth) => { + const widget = this.widgetByPos(position) + await widget.hover() + const widthButton = widget.locator('.widget-wrapper__size-btn') + await expect(widthButton).toBeVisible() + await widthButton.click() + const activePopup = this.page.locator('.popup__content:visible') + await expect(activePopup).toBeVisible() + const widthOptions = activePopup.locator('.popup-button-list__button') + await widthOptions.getByText(width).click() + const slug = await widget.getAttribute('data-slug') + if (!slug) { + throw new Error(`Widget at position ${position} has no slug`) + } + await this.assertWidget(position, slug, width) + } + + assertWidthRange = async (arg: { max: WidgetWidth; min: WidgetWidth; position: number }) => { + const widget = this.widgetByPos(arg.position) + await widget.hover() + const widthButton = widget.locator('.widget-wrapper__size-btn') + await expect(widthButton).toBeVisible() + if (await widthButton.isDisabled()) { + await expect(widget).toHaveAttribute('data-width', arg.min) + await expect(widget).toHaveAttribute('data-width', arg.max) + return + } + await widthButton.click() + const activePopup = this.page.locator('.popup__content:visible') + await expect(activePopup).toBeVisible() + const widthOptions = activePopup.locator('.popup-button-list__button') + await expect(widthOptions.first().locator('span').first()).toHaveText(arg.min) + await expect(widthOptions.last().locator('span').first()).toHaveText(arg.max) + } + + assertWidget = async (pos: number, slug: string, width: WidgetWidth) => { + const widget = this.widgetByPos(pos) + await expect(widget).toHaveAttribute('data-slug', new RegExp(`^${slug}`)) + await expect(widget).toHaveAttribute('data-width', width) + } + + setEditing = async () => { + await this.stepNavLast.locator('button').click() + await this.stepNavLast.getByText('Edit Dashboard').click() + await expect(this.stepNavLast.getByText('Editing Dashboard')).toBeVisible() + } + + resetLayout = async () => { + await this.stepNavLast.locator('button').click() + await this.stepNavLast.getByText('Reset Layout').click() + } + + assertIsEditing = async (shouldBe: boolean) => { + if (shouldBe) { + await expect(this.stepNavLast.getByText('Editing Dashboard')).toBeVisible() + await expect(this.stepNavLast.locator('button')).toHaveCount(3) + await expect(this.stepNavLast.locator('button').nth(0)).toHaveText('Add +') + await expect(this.stepNavLast.locator('button').nth(1)).toHaveText('Save Changes') + await expect(this.stepNavLast.locator('button').nth(2)).toHaveText('Cancel') + } else { + await expect(this.stepNavLast.locator('button')).toHaveCount(1) + await expect(this.stepNavLast.getByTitle('Dashboard')).toBeVisible() + } + } + + addWidget = async (slug: string) => { + const widgetsCount = await this.widgets.count() + await this.stepNavLast.locator('button').nth(0).click() + await this.page.locator('.drawer__content').getByText(slug).click() + await expect(this.widgets).toHaveCount(widgetsCount + 1) + // Wait for highlight animation to complete (1.5s animation + buffer) + await this.page.waitForTimeout(1600) + } + + openAddWidgetDrawer = async () => { + await this.stepNavLast.locator('button').nth(0).click() + await expect(this.page.locator('.drawer__content')).toBeVisible() + } + + getWidgetLabelsInDrawer = async (): Promise => { + const labels: string[] = [] + const cards = this.page.locator('.drawer__content .thumbnail-card__label') + const count = await cards.count() + for (let i = 0; i < count; i++) { + const text = await cards.nth(i).textContent() + if (text) { + labels.push(text) + } + } + return labels + } + + deleteWidget = async (position: number) => { + const widgetsCount = await this.widgets.count() + const widget = this.widgetByPos(position) + const widgetDomElem = await widget.elementHandle() + await widget.hover() + await widget.getByText('Delete widget').click() + expect(await widgetDomElem?.isHidden()).toBe(true) + await expect(this.widgets).toHaveCount(widgetsCount - 1) + } + + cancelEditing = async () => { + await this.stepNavLast.locator('button').nth(2).click() + const confirmButton = this.page.locator('#confirm-action') + await confirmButton.click() + await this.assertIsEditing(false) + // Wait for any layout changes/transitions to settle + await this.page.waitForTimeout(200) + } + + saveChangesAndValidate = async () => { + const snapshot = await this.getSnapshot() + await this.assertIsEditing(true) + await this.stepNavLast.locator('button').nth(1).click() + await this.assertIsEditing(false) + await this.validateLayout() + await this.page.reload() + await this.validateLayout() + const snapshotAfter = await this.getSnapshot() + expect(snapshotAfter).toEqual(snapshot) + } + + moveWidget = async (from: number, to: number, place: 'after' | 'before' = 'before') => { + const srcWidget = this.widgetByPos(from) + const srcWidgetBox = (await srcWidget.boundingBox())! + const targetWidget = this.widgetByPos(to) + const snapshot = await this.getSnapshot() + + // there are two droppable widgets for each widget: one before and one after + await expect(this.page.locator('.droppable-widget')).toHaveCount(snapshot.length * 2) + + // all droppable widgets should be transparent + for (const droppable of await this.page.locator('.droppable-widget').all()) { + const bgColor = await droppable.evaluate((el) => window.getComputedStyle(el).backgroundColor) + expect(bgColor).toBe('rgba(0, 0, 0, 0)') // transparent + } + + // here we make the DnD + await this.page.mouse.move( + srcWidgetBox.x + srcWidgetBox.width / 2, + srcWidgetBox.y + srcWidgetBox.height / 2, + ) + await this.page.mouse.down() + await targetWidget.scrollIntoViewIfNeeded() + const targetWidgetBox = (await targetWidget.boundingBox())! + await this.page.mouse.move( + targetWidgetBox.x + targetWidgetBox.width / 2 + (place === 'after' ? 5 : -5), + targetWidgetBox.y + targetWidgetBox.height / 2, + { + // steps is important: move slightly to trigger the drag sensor of DnD-kit + steps: 10, + }, + ) + // the droppable widget should be highlighted + const droppable = this.page.getByTestId(`${snapshot[to - 1]![0]}-${place}`) + const bgColor = await droppable.evaluate((el) => window.getComputedStyle(el).backgroundColor) + expect(bgColor).not.toBe('rgba(0, 0, 0, 0)') + await this.page.mouse.up() + await this.page.waitForTimeout(400) // dndkit animation + + // validate that the move was successful with the new order + const snapshotAfter = await this.getSnapshot() + const expectedSnapshot = moveArrayItem(snapshot, from, to, place) + expect(snapshotAfter).toEqual(expectedSnapshot) + } +} + +// utility function to move an item in an array +// from and to are 1-based positions (not 0-based indices) +function moveArrayItem( + arr: T[], + from: number, + to: number, + place: 'after' | 'before' = 'before', +): T[] { + const copy: T[] = [...arr] + + // Convert 1-based positions to 0-based indices + const fromIndex = from - 1 + const toIndex = to - 1 + + const item = copy.splice(fromIndex, 1)[0]! + + let insertIndex = toIndex + if (place === 'after') { + insertIndex = toIndex + 1 + } + + // Adjust insert index if we removed an item before it + if (fromIndex < insertIndex) { + insertIndex -= 1 + } + + copy.splice(insertIndex, 0, item) + + return copy +} diff --git a/test/helpers.ts b/test/helpers.ts index 995944c055e..ca09157849b 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -362,7 +362,9 @@ export function initPageConsoleErrorCatch(page: Page, options?: { ignoreCORS?: b // "Failed to fetch RSC payload for" happens seemingly randomly. There are lots of issues in the next.js repository for this. Causes e2e tests to fail and flake. Will ignore for now // the the server responded with a status of error happens frequently. Will ignore it for now. // Most importantly, this should catch react errors. - throw new Error(`Browser console error: ${msg.text()}`) + const { url, lineNumber, columnNumber } = msg.location() || {} + const locationSuffix = url ? `\n at ${url}:${lineNumber ?? 0}:${columnNumber ?? 0}` : '' + throw new Error(`Browser console error: ${msg.text()}${locationSuffix}`) } // Log ignored CORS-related errors for visibility @@ -379,9 +381,12 @@ export function initPageConsoleErrorCatch(page: Page, options?: { ignoreCORS?: b // Capture uncaught errors that do not appear in the console page.on('pageerror', (error) => { if (shouldCollectErrors) { - consoleErrors.push(`Page error: ${error.message}`) + const stack = error?.stack + const message = error?.message ?? String(error) + consoleErrors.push(`Page error: ${message}${stack ? `\n${stack}` : ''}`) } else { - throw new Error(`Page error: ${error.message}`) + // Rethrow the original error to preserve stack, name, and other metadata + throw error } }) diff --git a/test/locked-documents/e2e.spec.ts b/test/locked-documents/e2e.spec.ts index e7d6a56146b..d096505009e 100644 --- a/test/locked-documents/e2e.spec.ts +++ b/test/locked-documents/e2e.spec.ts @@ -1502,7 +1502,7 @@ describe('Locked Documents', () => { test('should show lock on document card in dashboard view if locked', async () => { await page.goto(postsUrl.admin) - await expect(page.locator('.dashboard__card-list #card-menu .locked svg')).toBeVisible() + await expect(page.locator('.collections__card-list #card-menu .locked svg')).toBeVisible() }) test('should not show lock on document card in dashboard view if unlocked', async () => { @@ -1516,7 +1516,7 @@ describe('Locked Documents', () => { await page.goto(postsUrl.admin) - await expect(page.locator('.dashboard__card-list #card-menu .locked')).toBeHidden() + await expect(page.locator('.collections__card-list #card-menu .locked')).toBeHidden() }) test('should not show lock on document card in dashboard view if locked by current user', async () => { @@ -1529,13 +1529,13 @@ describe('Locked Documents', () => { await page.goto(postsUrl.admin) - await expect(page.locator('.dashboard__card-list #card-menu .locked')).toBeHidden() + await expect(page.locator('.collections__card-list #card-menu .locked')).toBeHidden() }) test('should not show lock on document card in dashboard view if lock expired', async () => { await page.goto(postsUrl.admin) - await expect(page.locator('.dashboard__card-list #card-admin .locked svg')).toBeVisible() + await expect(page.locator('.collections__card-list #card-admin .locked svg')).toBeVisible() // Need to wait for lock duration to expire (lockDuration: 10 seconds) // eslint-disable-next-line payload/no-wait-function @@ -1543,7 +1543,7 @@ describe('Locked Documents', () => { await page.reload() - await expect(page.locator('.dashboard__card-list #card-admin .locked')).toBeHidden() + await expect(page.locator('.collections__card-list #card-admin .locked')).toBeHidden() await payload.delete({ collection: lockedDocumentCollection, @@ -1566,7 +1566,7 @@ describe('Locked Documents', () => { await page.goto(postsUrl.admin) - await expect(page.locator('.dashboard__card-list #card-admin .locked svg')).toBeVisible() + await expect(page.locator('.collections__card-list #card-admin .locked svg')).toBeVisible() // Need to wait for lock duration to expire (lockDuration: 10 seconds) // eslint-disable-next-line payload/no-wait-function @@ -1574,7 +1574,7 @@ describe('Locked Documents', () => { await page.reload() - await expect(page.locator('.dashboard__card-list #card-admin .locked')).toBeHidden() + await expect(page.locator('.collections__card-list #card-admin .locked')).toBeHidden() await page.locator('.card-admin a').click() diff --git a/test/package.json b/test/package.json index 6f71156586d..144b6b3173c 100644 --- a/test/package.json +++ b/test/package.json @@ -21,6 +21,9 @@ "templates/website/**/*": "sh -c \"cd templates/website; pnpm install --ignore-workspace --frozen-lockfile; pnpm run lint --fix\"", "tsconfig.json": "node scripts/reset-tsconfig.js" }, + "dependencies": { + "recharts": "3.2.1" + }, "devDependencies": { "@aws-sdk/client-s3": "^3.614.0", "@azure/storage-blob": "^12.11.0", diff --git a/tsconfig.base.json b/tsconfig.base.json index c79d70dc84f..71831b45536 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -21,8 +21,15 @@ "skipLibCheck": true, "emitDeclarationOnly": true, "sourceMap": true, - "lib": ["DOM", "DOM.Iterable", "ES2022"], - "types": ["node", "jest"], + "lib": [ + "DOM", + "DOM.Iterable", + "ES2022" + ], + "types": [ + "node", + "jest" + ], "incremental": true, "isolatedModules": true, "plugins": [ @@ -31,40 +38,84 @@ } ], "paths": { - "@payload-config": ["./test/_community/config.ts"], - "@payloadcms/admin-bar": ["./packages/admin-bar/src"], - "@payloadcms/live-preview": ["./packages/live-preview/src"], - "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], - "@payloadcms/live-preview-vue": ["./packages/live-preview-vue/src/index.ts"], - "@payloadcms/ui": ["./packages/ui/src/exports/client/index.ts"], - "@payloadcms/ui/shared": ["./packages/ui/src/exports/shared/index.ts"], - "@payloadcms/ui/rsc": ["./packages/ui/src/exports/rsc/index.ts"], - "@payloadcms/ui/scss": ["./packages/ui/src/scss.scss"], - "@payloadcms/ui/scss/app.scss": ["./packages/ui/src/scss/app.scss"], - "@payloadcms/next/*": ["./packages/next/src/exports/*.ts"], + "@payload-config": [ + "./test/admin/config.ts" + ], + "@payloadcms/admin-bar": [ + "./packages/admin-bar/src" + ], + "@payloadcms/live-preview": [ + "./packages/live-preview/src" + ], + "@payloadcms/live-preview-react": [ + "./packages/live-preview-react/src/index.ts" + ], + "@payloadcms/live-preview-vue": [ + "./packages/live-preview-vue/src/index.ts" + ], + "@payloadcms/ui": [ + "./packages/ui/src/exports/client/index.ts" + ], + "@payloadcms/ui/shared": [ + "./packages/ui/src/exports/shared/index.ts" + ], + "@payloadcms/ui/rsc": [ + "./packages/ui/src/exports/rsc/index.ts" + ], + "@payloadcms/ui/scss": [ + "./packages/ui/src/scss.scss" + ], + "@payloadcms/ui/scss/app.scss": [ + "./packages/ui/src/scss/app.scss" + ], + "@payloadcms/next/*": [ + "./packages/next/src/exports/*.ts" + ], "@payloadcms/richtext-lexical/client": [ "./packages/richtext-lexical/src/exports/client/index.ts" ], - "@payloadcms/richtext-lexical/rsc": ["./packages/richtext-lexical/src/exports/server/rsc.ts"], - "@payloadcms/richtext-slate/rsc": ["./packages/richtext-slate/src/exports/server/rsc.ts"], - "@payloadcms/plugin-ecommerce/ui": ["./packages/plugin-ecommerce/src/exports/ui.ts"], - "@payloadcms/plugin-ecommerce/react": ["./packages/plugin-ecommerce/src/exports/react.ts"], - "@payloadcms/plugin-ecommerce/types": ["./packages/plugin-ecommerce/src/exports/types.ts"], + "@payloadcms/richtext-lexical/rsc": [ + "./packages/richtext-lexical/src/exports/server/rsc.ts" + ], + "@payloadcms/richtext-slate/rsc": [ + "./packages/richtext-slate/src/exports/server/rsc.ts" + ], + "@payloadcms/plugin-ecommerce/ui": [ + "./packages/plugin-ecommerce/src/exports/ui.ts" + ], + "@payloadcms/plugin-ecommerce/react": [ + "./packages/plugin-ecommerce/src/exports/react.ts" + ], + "@payloadcms/plugin-ecommerce/types": [ + "./packages/plugin-ecommerce/src/exports/types.ts" + ], "@payloadcms/richtext-slate/client": [ "./packages/richtext-slate/src/exports/client/index.ts" ], - "@payloadcms/plugin-seo/client": ["./packages/plugin-seo/src/exports/client.ts"], - "@payloadcms/plugin-sentry/client": ["./packages/plugin-sentry/src/exports/client.ts"], - "@payloadcms/plugin-stripe/client": ["./packages/plugin-stripe/src/exports/client.ts"], - "@payloadcms/plugin-search/client": ["./packages/plugin-search/src/exports/client.ts"], + "@payloadcms/plugin-seo/client": [ + "./packages/plugin-seo/src/exports/client.ts" + ], + "@payloadcms/plugin-sentry/client": [ + "./packages/plugin-sentry/src/exports/client.ts" + ], + "@payloadcms/plugin-stripe/client": [ + "./packages/plugin-stripe/src/exports/client.ts" + ], + "@payloadcms/plugin-search/client": [ + "./packages/plugin-search/src/exports/client.ts" + ], "@payloadcms/plugin-form-builder/client": [ "./packages/plugin-form-builder/src/exports/client.ts" ], "@payloadcms/plugin-import-export/rsc": [ "./packages/plugin-import-export/src/exports/rsc.ts" ], - "@payloadcms/plugin-mcp": ["./packages/plugin-mcp/src/index.ts"], - "@payloadcms/plugin-multi-tenant/rsc": ["./packages/plugin-multi-tenant/src/exports/rsc.ts"], + "@payloadcms/plugin-mcp": [ + "./packages/plugin-mcp/src/index.ts" + ], + "@payloadcms/plugin-multi-tenant/rsc": [ + "./packages/plugin-multi-tenant/src/exports/rsc.ts" + ], "@payloadcms/plugin-multi-tenant/utilities": [ "./packages/plugin-multi-tenant/src/exports/utilities.ts" ], @@ -74,25 +125,42 @@ "@payloadcms/plugin-multi-tenant/client": [ "./packages/plugin-multi-tenant/src/exports/client.ts" ], - "@payloadcms/plugin-multi-tenant": ["./packages/plugin-multi-tenant/src/index.ts"], + "@payloadcms/plugin-multi-tenant": [ + "./packages/plugin-multi-tenant/src/index.ts" + ], "@payloadcms/plugin-multi-tenant/translations/languages/all": [ "./packages/plugin-multi-tenant/src/translations/index.ts" ], "@payloadcms/plugin-multi-tenant/translations/languages/*": [ "./packages/plugin-multi-tenant/src/translations/languages/*.ts" ], - "@payloadcms/next": ["./packages/next/src/exports/*"], - "@payloadcms/storage-azure/client": ["./packages/storage-azure/src/exports/client.ts"], - "@payloadcms/storage-s3/client": ["./packages/storage-s3/src/exports/client.ts"], + "@payloadcms/next": [ + "./packages/next/src/exports/*" + ], + "@payloadcms/storage-azure/client": [ + "./packages/storage-azure/src/exports/client.ts" + ], + "@payloadcms/storage-s3/client": [ + "./packages/storage-s3/src/exports/client.ts" + ], "@payloadcms/storage-vercel-blob/client": [ "./packages/storage-vercel-blob/src/exports/client.ts" ], - "@payloadcms/storage-gcs/client": ["./packages/storage-gcs/src/exports/client.ts"], + "@payloadcms/storage-gcs/client": [ + "./packages/storage-gcs/src/exports/client.ts" + ], "@payloadcms/storage-uploadthing/client": [ "./packages/storage-uploadthing/src/exports/client.ts" ] } }, - "include": ["${configDir}/src"], - "exclude": ["${configDir}/dist", "${configDir}/build", "${configDir}/temp", "**/*.spec.ts"] + "include": [ + "${configDir}/src" + ], + "exclude": [ + "${configDir}/dist", + "${configDir}/build", + "${configDir}/temp", + "**/*.spec.ts" + ] } From 3c18be67f26c7aac5802839dc0acd9716c806db1 Mon Sep 17 00:00:00 2001 From: German Jablonski <43938777+GermanJablo@users.noreply.github.com> Date: Fri, 19 Dec 2025 15:44:55 +0000 Subject: [PATCH 30/67] fix(richtext-lexical): blocksFeature with relationship exposes other tenants (#14985) Fixes #14823 The issue is essentially the same problem that PR #13229 fixed, but for a different Lexical feature: | PR #13229 | PR #14985 (this one) | | --- | --- | | Link Feature with internal links | BlocksFeature with relationship fields inside blocks | | Relationship to documents exposes other tenants | Relationship inside blocks exposes other tenants | ## Root Cause The multi tenant plugin applies tenant filters to relationship fields using `addFilterOptionsToFields()`, which only runs on collection fields. However: - BlocksFeature defines blocks via feature props rather than collection fields - These blocks are processed independently through `sanitizeFields()` - Relationship fields inside blocks never receive the collection baseFilter --- .../src/features/blocks/server/index.ts | 13 ++- .../src/utilities/applyBaseFilterToFields.ts | 109 ++++++++++++++++++ .../collections/MenuItems.ts | 20 ++++ test/plugin-multi-tenant/e2e.spec.ts | 39 +++++++ 4 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 packages/richtext-lexical/src/utilities/applyBaseFilterToFields.ts diff --git a/packages/richtext-lexical/src/features/blocks/server/index.ts b/packages/richtext-lexical/src/features/blocks/server/index.ts index 0643efe56a1..e3fec983cd5 100644 --- a/packages/richtext-lexical/src/features/blocks/server/index.ts +++ b/packages/richtext-lexical/src/features/blocks/server/index.ts @@ -9,6 +9,7 @@ import type { import { fieldsToJSONSchema, flattenAllFields, sanitizeFields } from 'payload' +import { applyBaseFilterToFields } from '../../../utilities/applyBaseFilterToFields.js' import { createServerFeature } from '../../../utilities/createServerFeature.js' import { createNode } from '../../typeUtilities.js' import { blockPopulationPromiseHOC } from './graphQLPopulationPromise.js' @@ -58,7 +59,11 @@ export const BlocksFeature = createServerFeature { + // Handle relationship fields + if (field.type === 'relationship') { + const relationshipField = field + + // Store the original filterOptions + const originalFilterOptions = relationshipField.filterOptions + + // Create new filterOptions that includes baseFilter + relationshipField.filterOptions = async (args) => { + const { relationTo, req, user } = args + + // Call original filterOptions if it exists + const originalResult = + typeof originalFilterOptions === 'function' + ? await originalFilterOptions(args) + : (originalFilterOptions ?? true) + + // If original filter returns false, respect that + if (originalResult === false) { + return false + } + + // Get the collection's admin config + const admin = config.collections.find(({ slug }) => slug === relationTo)?.admin + + // Check if collection is hidden + const hidden = admin?.hidden + if (typeof hidden === 'function' && hidden({ user } as { user: TypedUser })) { + return false + } + + // Apply baseFilter (with backwards compatibility for baseListFilter) + const baseFilter = admin?.baseFilter ?? admin?.baseListFilter + const baseFilterResult = await baseFilter?.({ + limit: 0, + page: 1, + req, + sort: 'id', + }) + + // If no baseFilter, return original result + if (!baseFilterResult) { + return originalResult + } + + // If original result is true, just return the baseFilter + if (originalResult === true) { + return baseFilterResult + } + + // Combine original and baseFilter results + return combineWhereConstraints([originalResult, baseFilterResult], 'and') + } + + return relationshipField + } + + // Recursively process nested fields + if ('fields' in field && field.fields) { + return { + ...field, + fields: applyBaseFilterToFields(field.fields, config), + } + } + + // Handle tabs + if (field.type === 'tabs' && 'tabs' in field) { + return { + ...field, + tabs: field.tabs.map((tab) => ({ + ...tab, + fields: applyBaseFilterToFields(tab.fields, config), + })), + } + } + + // Handle blocks + if (field.type === 'blocks') { + const blocks = (field.blockReferences ?? field.blocks ?? []) as Block[] + return { + ...field, + blocks: blocks.map((block) => { + if (typeof block === 'string') { + return block + } + return { + ...block, + fields: applyBaseFilterToFields(block.fields, config), + } + }), + } + } + + return field + }) +} diff --git a/test/plugin-multi-tenant/collections/MenuItems.ts b/test/plugin-multi-tenant/collections/MenuItems.ts index a02809c17db..769143918bb 100644 --- a/test/plugin-multi-tenant/collections/MenuItems.ts +++ b/test/plugin-multi-tenant/collections/MenuItems.ts @@ -1,6 +1,7 @@ import type { Access, CollectionConfig, Where } from 'payload' import { getUserTenantIDs } from '@payloadcms/plugin-multi-tenant/utilities' +import { BlocksFeature, lexicalEditor } from '@payloadcms/richtext-lexical' import { menuItemsSlug, notTenantedSlug, relationshipsSlug } from '../shared.js' @@ -96,6 +97,25 @@ export const MenuItems: CollectionConfig = { { name: 'content', type: 'richText', + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + BlocksFeature({ + blocks: [ + { + slug: 'block-with-relationship', + fields: [ + { + name: 'relationship', + type: 'relationship', + relationTo: 'food-menu', + }, + ], + }, + ], + }), + ], + }), }, { name: 'polymorphicRelationship', diff --git a/test/plugin-multi-tenant/e2e.spec.ts b/test/plugin-multi-tenant/e2e.spec.ts index 584307a0b23..63a7d730de0 100644 --- a/test/plugin-multi-tenant/e2e.spec.ts +++ b/test/plugin-multi-tenant/e2e.spec.ts @@ -416,6 +416,45 @@ test.describe('Multi Tenant', () => { await expect(page.getByText('Chorizo Con Queso')).toBeVisible() await expect(page.getByText('Pretzel Bites')).toBeHidden() }) + + test('should filter relationship fields in Lexical BlocksFeature', async () => { + await loginClientSide({ + data: credentials.admin, + page, + serverURL, + }) + await page.goto(menuItemsURL.create) + await selectDocumentTenant({ + page, + payload, + tenant: 'Blue Dog', + }) + + // Fill in the required name field + await page.fill('#field-name', 'Test Menu Item') + + // Find the bug-repro richtext field and insert a block + const rte = page.locator('.rich-text-lexical [data-lexical-editor="true"]') + await rte.click() + await rte.focus() + + // Open slash menu and insert block + await page.keyboard.type('/') + await expect(page.locator('.slash-menu-popup')).toBeVisible() + await page.getByText('Block With Relationship').click() + + // Wait for block to be inserted + await expect(page.locator('.LexicalEditorTheme__block')).toBeVisible() + + // Open the relationship field in the block + await page.locator('.LexicalEditorTheme__block .rs__input').click() + + // Should only show Blue Dog Menu, not Steel Cat Menu or others + await expect(page.getByText('Blue Dog Menu')).toBeVisible() + await expect(page.getByText('Steel Cat Menu')).toBeHidden() + await expect(page.getByText('Anchor Bar Menu')).toBeHidden() + await expect(page.locator('.rs__menu')).toHaveCount(1) + }) }) test.describe('Globals', () => { From 5ab3497d03bf67fea0300f6d329cc995189381be Mon Sep 17 00:00:00 2001 From: Jarrod Flesch <30633324+JarrodMFlesch@users.noreply.github.com> Date: Fri, 19 Dec 2025 11:13:21 -0500 Subject: [PATCH 31/67] fix: basePath not working properly with admin routes (#14967) This PR adds a base-path test suite, updates the formatAdminURL helper function. The helper function allows you to create routes inside the admin panel that take `basePath` into account when set. There are a lot of touched files here, most have the same treatment. ## API URL construction changes Previously we were appending the basePath in the default api configuration. That is no longer the case and is more predictable to use the helper function that will generate a correct path/url. ## Admin URL construction changes The default admin route differed from the default api route, the default admin route did not prepend the basePath. The reason it did not/should not, is because `usePathname` from NextJS excludes basePath. So if we were to prepend it to `routes.admin` and then for example use `pathname.startsWith(config.routes.admin)` it would always return false when using a basePath, since `/route` will never start with `/basePath/route`. Also, when you do something like `router.push(/adminRoute)` NextJS will prepend the basePath and push you to `/basePath/adminRoute`. If we prepended it in the config it would push you to `/basePath/basePath/adminRoute`. ## Helper function usage The helper is especially useful for plugin work, this way your plugin will generate correct urls for users using basePath. Before we were doing: ```ts // worked because we prepended basePath to apiRoute const apiURL = `${serverURL}${apiRoute}/collections/${slug}/${id}` // never worked since basePath was never prepended to adminRoute const adminURL = `${serverURL}${adminRoute}/collections/${slug}/${id}` ``` Now we can do: ```ts import { formatAdminURL } from 'payload/shared' // Admin url example const adminURL = formatAdminURL({ adminRoute: config.routes.admin, path: `/collections/${slug}/${id}`, }) // API url example const apiURL = formatAdminURL({ apiRoute: config.routes.api, path: `/collections/${slug}/${id}`, // serverURL, when supplied returns a full url }) ``` If you pass `serverURL` the result will be a full URL. If excluded the result will be a relative path. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/post-release-templates.yml | 8 +- docs/fields/rich-text.mdx | 1 - examples/astro/payload/docker-compose.yml | 6 +- examples/remix/payload/docker-compose.yml | 6 +- next.config.mjs | 1 + package.json | 2 +- packages/live-preview/src/mergeData.ts | 14 +- .../DocumentHeader/Tabs/Tab/TabLink.tsx | 4 +- .../next/src/elements/Nav/index.client.tsx | 6 +- .../next/src/routes/graphql/playground.ts | 7 +- packages/next/src/routes/rest/index.ts | 8 +- .../next/src/utilities/handleAuthRedirect.ts | 1 - packages/next/src/views/API/index.client.tsx | 10 +- .../views/Account/ResetPreferences/index.tsx | 22 ++- .../next/src/views/Account/Settings/index.tsx | 6 +- packages/next/src/views/Account/index.tsx | 6 +- .../src/views/BrowseByFolder/buildView.tsx | 1 - .../src/views/CollectionFolders/buildView.tsx | 1 - .../views/CreateFirstUser/index.client.tsx | 6 +- packages/next/src/views/Document/index.tsx | 7 +- .../next/src/views/ForgotPassword/index.tsx | 3 - packages/next/src/views/List/index.tsx | 1 - .../next/src/views/Login/LoginForm/index.tsx | 6 +- .../next/src/views/Logout/LogoutClient.tsx | 1 - .../ResetPassword/ResetPasswordForm/index.tsx | 8 +- .../next/src/views/ResetPassword/index.tsx | 2 - packages/next/src/views/Root/getRouteData.ts | 2 - packages/next/src/views/Root/index.tsx | 6 +- .../next/src/views/Unauthorized/index.tsx | 2 - packages/next/src/views/Verify/index.tsx | 2 +- .../src/views/Version/Default/SetStepNav.tsx | 6 - .../next/src/views/Version/Restore/index.tsx | 8 +- .../views/Versions/cells/CreatedAt/index.tsx | 3 - packages/next/src/views/Versions/index.tsx | 5 +- .../payload/src/auth/sendVerificationEmail.ts | 8 +- packages/payload/src/config/defaults.ts | 2 +- packages/payload/src/exports/shared.ts | 1 - packages/payload/src/index.ts | 15 +- packages/payload/src/uploads/getBaseFields.ts | 13 +- .../src/utilities/createPayloadRequest.ts | 8 +- .../src/utilities/formatAdminURL.spec.ts | 38 +++-- .../payload/src/utilities/formatAdminURL.ts | 73 ++++++---- .../payload/src/utilities/formatApiURL.ts | 18 --- .../payload/src/utilities/handleEndpoints.ts | 11 +- .../src/client/createClientUploadHandler.tsx | 4 +- .../src/react/provider/index.tsx | 9 +- .../src/components/ExportSaveButton/index.tsx | 24 ++-- .../TenantSelectionProvider/index.client.tsx | 8 +- .../src/utilities/getGlobalViewRedirect.ts | 8 +- .../src/Search/ui/LinkToDoc/index.client.tsx | 10 +- .../Search/ui/ReindexButton/index.client.tsx | 17 ++- .../MetaDescriptionComponent.tsx | 9 +- .../fields/MetaImage/MetaImageComponent.tsx | 7 +- .../fields/MetaTitle/MetaTitleComponent.tsx | 8 +- .../src/fields/Preview/PreviewComponent.tsx | 9 +- .../floatingLinkEditor/LinkEditor/index.tsx | 24 ++-- .../components/RelationshipComponent.tsx | 5 +- .../upload/client/component/index.tsx | 4 +- .../elements/relationship/Element/index.tsx | 5 +- .../field/elements/upload/Element/index.tsx | 5 +- .../src/client/AzureClientUploadHandler.ts | 8 +- .../src/client/GcsClientUploadHandler.ts | 8 +- .../src/client/S3ClientUploadHandler.ts | 8 +- .../client/UploadthingClientUploadHandler.ts | 8 +- .../client/VercelBlobClientUploadHandler.ts | 8 +- packages/ui/src/elements/AppHeader/index.tsx | 2 +- packages/ui/src/elements/Autosave/index.tsx | 25 +++- .../BulkUpload/FormsManager/index.tsx | 15 +- .../ui/src/elements/CopyLocaleData/index.tsx | 3 - .../elements/DefaultListViewTabs/index.tsx | 1 - .../ui/src/elements/DeleteDocument/index.tsx | 15 +- packages/ui/src/elements/DeleteMany/index.tsx | 33 +++-- .../src/elements/DocumentControls/index.tsx | 1 - .../src/elements/DuplicateDocument/index.tsx | 6 +- .../src/elements/EditMany/DrawerContent.tsx | 12 +- .../FolderView/BrowseByFolderButton/index.tsx | 2 - .../elements/FolderView/Cell/index.client.tsx | 28 ++-- .../FolderView/CurrentFolderActions/index.tsx | 18 ++- .../FolderView/MoveDocToFolder/index.tsx | 11 +- packages/ui/src/elements/IDLabel/index.tsx | 2 - .../TitleActions/ListEmptyTrashButton.tsx | 11 +- packages/ui/src/elements/Logout/index.tsx | 2 - .../PermanentlyDeleteButton/index.tsx | 20 ++- .../PublishButton/ScheduleDrawer/index.tsx | 5 +- .../ui/src/elements/PublishButton/index.tsx | 22 ++- .../elements/PublishMany/DrawerContent.tsx | 10 +- .../QueryPresets/QueryPresetBar/index.tsx | 20 +-- .../ui/src/elements/RestoreButton/index.tsx | 20 ++- .../ui/src/elements/RestoreMany/index.tsx | 33 +++-- .../ui/src/elements/SaveDraftButton/index.tsx | 24 ++-- packages/ui/src/elements/Status/index.tsx | 56 ++++---- .../ui/src/elements/StayLoggedIn/index.tsx | 4 +- .../DefaultCell/fields/Relationship/index.tsx | 12 +- .../src/elements/Table/DefaultCell/index.tsx | 2 - .../ui/src/elements/Table/OrderableTable.tsx | 21 ++- .../Table/RelationshipProvider/index.tsx | 7 +- .../elements/UnpublishMany/DrawerContent.tsx | 10 +- packages/ui/src/elements/Upload/index.tsx | 13 +- .../Condition/Relationship/index.tsx | 24 ++-- packages/ui/src/fields/Relationship/Input.tsx | 49 ++++--- packages/ui/src/fields/Upload/Input.tsx | 29 ++-- packages/ui/src/graphics/Account/index.tsx | 3 +- packages/ui/src/providers/Auth/index.tsx | 33 ++--- .../ui/src/providers/DocumentInfo/index.tsx | 50 ++++--- .../DocumentInfo/useGetDocPermissions.tsx | 39 +++--- packages/ui/src/providers/Folders/index.tsx | 43 +++--- packages/ui/src/providers/Locale/index.tsx | 7 +- .../ui/src/providers/Preferences/index.tsx | 32 +++-- .../buildColumnState/renderCell.tsx | 1 - .../src/utilities/handleBackToDashboard.tsx | 2 +- packages/ui/src/utilities/handleGoBack.tsx | 1 - .../ui/src/views/CollectionFolder/index.tsx | 2 - packages/ui/src/views/Edit/Auth/index.tsx | 10 +- .../views/Edit/SetDocumentStepNav/index.tsx | 4 - packages/ui/src/views/Edit/index.tsx | 2 - packages/ui/src/views/List/index.tsx | 1 - .../ui/src/widgets/CollectionCards/index.tsx | 5 +- payload-types.ts | 4 +- templates/_template/docker-compose.yml | 6 +- templates/blank/docker-compose.yml | 6 +- .../src/components/BeforeDashboardClient.tsx | 8 +- templates/with-postgres/docker-compose.yml | 6 +- .../with-vercel-mongodb/docker-compose.yml | 6 +- .../with-vercel-postgres/docker-compose.yml | 6 +- test/_community/payload-types.ts | 1 + test/a11y/focus-indicators.e2e.spec.ts | 53 ++++--- test/access-control/e2e.spec.ts | 4 +- test/admin-bar/e2e.spec.ts | 3 +- test/admin-bar/payload-types.ts | 42 ++++++ test/admin-root/payload-types.ts | 42 ++++++ test/admin/config.ts | 2 + test/admin/e2e/document-view/e2e.spec.ts | 2 + test/admin/e2e/general/e2e.spec.ts | 132 ++++++++++++++---- test/admin/e2e/list-view/e2e.spec.ts | 3 +- test/admin/shared.ts | 2 + test/auth-basic/e2e.spec.ts | 10 +- test/auth/AuthDebug.tsx | 10 +- test/auth/config.ts | 3 + test/auth/e2e.spec.ts | 53 +++++-- test/auth/shared.ts | 2 + test/base-path/.gitignore | 4 + test/base-path/collections/Posts.ts | 19 +++ test/base-path/config.ts | 28 ++++ test/base-path/e2e.spec.ts | 83 +++++++++++ test/base-path/next-env.d.ts | 5 + test/base-path/seed/index.ts | 38 +++++ test/base-path/shared.ts | 1 + test/base-path/tsconfig.eslint.json | 4 + test/base-path/tsconfig.json | 26 ++++ test/dev.ts | 11 +- test/field-error-states/e2e.spec.ts | 19 ++- test/folders-browse-by-disabled/e2e.spec.ts | 11 +- test/folders/e2e.spec.ts | 62 ++++---- test/form-state/e2e.spec.ts | 69 +++++---- test/helpers.ts | 10 +- test/helpers/e2e/auth/login.ts | 9 +- test/helpers/e2e/auth/logout.ts | 7 +- test/helpers/e2e/goToListDoc.ts | 19 ++- test/helpers/reInitializeDB.ts | 14 +- test/helpers/sdk/index.ts | 23 ++- .../collections/Lexical/LexicalRendered.tsx | 25 ++-- test/localization/e2e.spec.ts | 7 +- test/server-functions/e2e.spec.ts | 19 ++- test/server-url/e2e.spec.ts | 1 - test/versions/config.ts | 3 +- test/versions/e2e.spec.ts | 55 +++++--- test/versions/shared.ts | 1 + .../payload/reference/PLUGIN-DEVELOPMENT.md | 8 +- tsconfig.base.json | 130 ++++------------- 169 files changed, 1576 insertions(+), 905 deletions(-) delete mode 100644 packages/payload/src/utilities/formatApiURL.ts create mode 100644 test/base-path/.gitignore create mode 100644 test/base-path/collections/Posts.ts create mode 100644 test/base-path/config.ts create mode 100644 test/base-path/e2e.spec.ts create mode 100644 test/base-path/next-env.d.ts create mode 100644 test/base-path/seed/index.ts create mode 100644 test/base-path/shared.ts create mode 100644 test/base-path/tsconfig.eslint.json create mode 100644 test/base-path/tsconfig.json diff --git a/.github/workflows/post-release-templates.yml b/.github/workflows/post-release-templates.yml index 9998114d18c..4da9d1f399e 100644 --- a/.github/workflows/post-release-templates.yml +++ b/.github/workflows/post-release-templates.yml @@ -62,7 +62,7 @@ jobs: - name: Start PostgreSQL uses: CasperWA/postgresql-action@v1.2 with: - postgresql version: "14" # See https://hub.docker.com/_/postgres for available versions + postgresql version: '14' # See https://hub.docker.com/_/postgres for available versions postgresql db: ${{ env.POSTGRES_DB }} postgresql user: ${{ env.POSTGRES_USER }} postgresql password: ${{ env.POSTGRES_PASSWORD }} @@ -108,13 +108,13 @@ jobs: uses: peter-evans/create-pull-request@v7 with: token: ${{ secrets.GH_TOKEN_POST_RELEASE_TEMPLATES }} - labels: "area: templates" + labels: 'area: templates' author: github-actions[bot] - commit-message: "templates: bump templates for ${{ needs.wait_for_release.outputs.release_tag }}" + commit-message: 'templates: bump templates for ${{ needs.wait_for_release.outputs.release_tag }}' branch: ${{ steps.commit.outputs.branch }} base: main assignees: ${{ github.actor }} - title: "templates: bump for ${{ needs.wait_for_release.outputs.release_tag }}" + title: 'templates: bump for ${{ needs.wait_for_release.outputs.release_tag }}' body: | 🤖 Automated bump of templates for ${{ needs.wait_for_release.outputs.release_tag }} diff --git a/docs/fields/rich-text.mdx b/docs/fields/rich-text.mdx index 7cc0cc95689..7acf1380a60 100644 --- a/docs/fields/rich-text.mdx +++ b/docs/fields/rich-text.mdx @@ -17,7 +17,6 @@ Instead, you can invest your time and effort into learning the underlying open-s caption="Admin Panel screenshot of a Rich Text field" /> - ## Config Options | Option | Description | diff --git a/examples/astro/payload/docker-compose.yml b/examples/astro/payload/docker-compose.yml index 4ed0d24c9ae..a93bd39918b 100644 --- a/examples/astro/payload/docker-compose.yml +++ b/examples/astro/payload/docker-compose.yml @@ -1,10 +1,10 @@ -version: "3" +version: '3' services: payload: image: node:18-alpine ports: - - "3000:3000" + - '3000:3000' volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -20,7 +20,7 @@ services: mongo: image: mongo:latest ports: - - "27017:27017" + - '27017:27017' command: - --storageEngine=wiredTiger volumes: diff --git a/examples/remix/payload/docker-compose.yml b/examples/remix/payload/docker-compose.yml index 4ed0d24c9ae..a93bd39918b 100644 --- a/examples/remix/payload/docker-compose.yml +++ b/examples/remix/payload/docker-compose.yml @@ -1,10 +1,10 @@ -version: "3" +version: '3' services: payload: image: node:18-alpine ports: - - "3000:3000" + - '3000:3000' volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -20,7 +20,7 @@ services: mongo: image: mongo:latest ports: - - "27017:27017" + - '27017:27017' command: - --storageEngine=wiredTiger volumes: diff --git a/next.config.mjs b/next.config.mjs index 59d971b1d34..f1b44a85006 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -14,6 +14,7 @@ const withBundleAnalyzer = bundleAnalyzer({ const config = withBundleAnalyzer( withPayload( { + basePath: process.env?.NEXT_BASE_PATH || undefined, eslint: { ignoreDuringBuilds: true, }, diff --git a/package.json b/package.json index 27b27e398cb..f139045eb0a 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "obliterate-playwright-cache-macos": "rm -rf ~/Library/Caches/ms-playwright && find /System/Volumes/Data/private/var/folders -type d -name 'playwright*' -exec rm -rf {} +", "prepare": "husky", "prepare-run-test-against-prod": "pnpm bf && rm -rf test/packed && rm -rf test/node_modules && rm -rf app && rm -f test/pnpm-lock.yaml && pnpm run script:pack --all --no-build --dest test/packed && pnpm runts test/setupProd.ts && cd test && pnpm i --ignore-workspace && cd ..", - "prepare-run-test-against-prod:ci": "rm -rf test/node_modules && rm -rf app && rm -f test/pnpm-lock.yaml && pnpm run script:pack --all --no-build --dest test/packed && pnpm runts test/setupProd.ts && cd test && pnpm i --ignore-workspace && cd ..", + "prepare-run-test-against-prod:ci": "rm -rf test/packed && rm -rf test/node_modules && rm -rf app && rm -f test/pnpm-lock.yaml && pnpm run script:pack --all --no-build --dest test/packed && pnpm runts test/setupProd.ts && cd test && pnpm i --ignore-workspace && cd ..", "publish-prerelease": "pnpm --filter releaser publish-prerelease", "reinstall": "pnpm clean:all && pnpm install", "release": "pnpm --filter releaser release --tag latest", diff --git a/packages/live-preview/src/mergeData.ts b/packages/live-preview/src/mergeData.ts index 6c7a367a074..f9548af2a32 100644 --- a/packages/live-preview/src/mergeData.ts +++ b/packages/live-preview/src/mergeData.ts @@ -1,12 +1,12 @@ +import { formatAdminURL } from 'payload/shared' + import type { CollectionPopulationRequestHandler } from './types.js' -const defaultRequestHandler: CollectionPopulationRequestHandler = ({ - apiPath, - data, - endpoint, - serverURL, -}) => { - const url = `${serverURL}${apiPath}/${endpoint}` +const defaultRequestHandler: CollectionPopulationRequestHandler = ({ apiPath, data, endpoint }) => { + const url = formatAdminURL({ + apiRoute: apiPath, + path: `/${endpoint}`, + }) return fetch(url, { body: JSON.stringify(data), diff --git a/packages/next/src/elements/DocumentHeader/Tabs/Tab/TabLink.tsx b/packages/next/src/elements/DocumentHeader/Tabs/Tab/TabLink.tsx index 814673f359f..fd890937121 100644 --- a/packages/next/src/elements/DocumentHeader/Tabs/Tab/TabLink.tsx +++ b/packages/next/src/elements/DocumentHeader/Tabs/Tab/TabLink.tsx @@ -1,7 +1,7 @@ 'use client' import type { SanitizedConfig } from 'payload' -import { Button, useConfig } from '@payloadcms/ui' +import { Button } from '@payloadcms/ui' import { useParams, usePathname, useSearchParams } from 'next/navigation.js' import { formatAdminURL } from 'payload/shared' import React from 'react' @@ -25,7 +25,6 @@ export const DocumentTabLink: React.FC<{ }) => { const pathname = usePathname() const params = useParams() - const { config } = useConfig() const searchParams = useSearchParams() @@ -37,7 +36,6 @@ export const DocumentTabLink: React.FC<{ let docPath = formatAdminURL({ adminRoute, path: `/${isCollection ? 'collections' : 'globals'}/${entitySlug}`, - serverURL: config.serverURL, }) if (isCollection) { diff --git a/packages/next/src/elements/Nav/index.client.tsx b/packages/next/src/elements/Nav/index.client.tsx index 344013feb04..d65fc56a8ec 100644 --- a/packages/next/src/elements/Nav/index.client.tsx +++ b/packages/next/src/elements/Nav/index.client.tsx @@ -28,7 +28,6 @@ export const DefaultNavClient: React.FC<{ }, folders, routes: { admin: adminRoute }, - serverURL, }, } = useConfig() @@ -37,7 +36,6 @@ export const DefaultNavClient: React.FC<{ const folderURL = formatAdminURL({ adminRoute, path: foldersRoute, - serverURL, }) const viewingRootFolderView = pathname.startsWith(folderURL) @@ -53,12 +51,12 @@ export const DefaultNavClient: React.FC<{ let id: string if (type === EntityType.collection) { - href = formatAdminURL({ adminRoute, path: `/collections/${slug}`, serverURL }) + href = formatAdminURL({ adminRoute, path: `/collections/${slug}` }) id = `nav-${slug}` } if (type === EntityType.global) { - href = formatAdminURL({ adminRoute, path: `/globals/${slug}`, serverURL }) + href = formatAdminURL({ adminRoute, path: `/globals/${slug}` }) id = `nav-global-${slug}` } diff --git a/packages/next/src/routes/graphql/playground.ts b/packages/next/src/routes/graphql/playground.ts index f7c7541b682..1550befae18 100644 --- a/packages/next/src/routes/graphql/playground.ts +++ b/packages/next/src/routes/graphql/playground.ts @@ -1,5 +1,6 @@ import { renderPlaygroundPage } from 'graphql-playground-html' import { createPayloadRequest, type SanitizedConfig } from 'payload' +import { formatAdminURL } from 'payload/shared' export const GET = (config: Promise) => async (request: Request) => { const req = await createPayloadRequest({ @@ -13,9 +14,13 @@ export const GET = (config: Promise) => async (request: Request process.env.NODE_ENV === 'production') || process.env.NODE_ENV !== 'production' ) { + const endpoint = formatAdminURL({ + apiRoute: req.payload.config.routes.api, + path: req.payload.config.routes.graphQL as `/${string}`, + }) return new Response( renderPlaygroundPage({ - endpoint: `${req.payload.config.routes.api}${req.payload.config.routes.graphQL}`, + endpoint, settings: { 'request.credentials': 'include', }, diff --git a/packages/next/src/routes/rest/index.ts b/packages/next/src/routes/rest/index.ts index 737b3854246..ed53f2a06a1 100644 --- a/packages/next/src/routes/rest/index.ts +++ b/packages/next/src/routes/rest/index.ts @@ -1,4 +1,5 @@ import { handleEndpoints, type SanitizedConfig } from 'payload' +import { formatAdminURL } from 'payload/shared' import { generateOGImage } from './og/index.js' @@ -34,9 +35,10 @@ const handlerBuilder = const response = await handleEndpoints({ config, - path: awaitedParams - ? `${awaitedConfig.routes.api}/${awaitedParams.slug.join('/')}` - : undefined, + path: formatAdminURL({ + apiRoute: awaitedConfig.routes.api, + path: awaitedParams ? `/${awaitedParams.slug.join('/')}` : undefined, + }), request, }) diff --git a/packages/next/src/utilities/handleAuthRedirect.ts b/packages/next/src/utilities/handleAuthRedirect.ts index 7e4b0de4840..be6f00d263b 100644 --- a/packages/next/src/utilities/handleAuthRedirect.ts +++ b/packages/next/src/utilities/handleAuthRedirect.ts @@ -31,7 +31,6 @@ export const handleAuthRedirect = ({ config, route, searchParams, user }: Args): const redirectTo = formatAdminURL({ adminRoute, path: user ? unauthorizedRoute : loginRouteFromConfig, - serverURL: config.serverURL, }) const parsedLoginRouteSearchParams = qs.parse(redirectTo.split('?')[1] ?? '') diff --git a/packages/next/src/views/API/index.client.tsx b/packages/next/src/views/API/index.client.tsx index bd0d31e30ab..4b7bbb6d3e4 100644 --- a/packages/next/src/views/API/index.client.tsx +++ b/packages/next/src/views/API/index.client.tsx @@ -18,7 +18,7 @@ import { useSearchParams } from 'next/navigation.js' import './index.scss' -import { hasDraftsEnabled } from 'payload/shared' +import { formatAdminURL, hasDraftsEnabled } from 'payload/shared' import * as React from 'react' import { LocaleSelector } from './LocaleSelector/index.js' @@ -38,7 +38,6 @@ export const APIViewClient: React.FC = () => { defaultDepth, localization, routes: { api: apiRoute }, - serverURL, }, getEntityConfig, } = useConfig() @@ -51,7 +50,7 @@ export const APIViewClient: React.FC = () => { localization.locales.map((locale) => ({ label: locale.label, value: locale.code })) let draftsEnabled: boolean = false - let docEndpoint: string = '' + let docEndpoint: `/${string}` = undefined if (collectionConfig) { draftsEnabled = hasDraftsEnabled(collectionConfig) @@ -81,7 +80,10 @@ export const APIViewClient: React.FC = () => { trash: trashParam ? 'true' : 'false', }).toString() - const fetchURL = `${serverURL}${apiRoute}${docEndpoint}?${params}` + const fetchURL = formatAdminURL({ + apiRoute, + path: `${docEndpoint}?${params}`, + }) React.useEffect(() => { const fetchData = async () => { diff --git a/packages/next/src/views/Account/ResetPreferences/index.tsx b/packages/next/src/views/Account/ResetPreferences/index.tsx index 57699ac0b33..aad2bf03049 100644 --- a/packages/next/src/views/Account/ResetPreferences/index.tsx +++ b/packages/next/src/views/Account/ResetPreferences/index.tsx @@ -1,19 +1,30 @@ 'use client' import type { TypedUser } from 'payload' -import { Button, ConfirmationModal, toast, useModal, useTranslation } from '@payloadcms/ui' -import { formatApiURL } from 'payload/shared' +import { + Button, + ConfirmationModal, + toast, + useConfig, + useModal, + useTranslation, +} from '@payloadcms/ui' +import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import { Fragment, useCallback } from 'react' const confirmResetModalSlug = 'confirm-reset-modal' export const ResetPreferences: React.FC<{ - readonly apiRoute: string readonly user?: TypedUser -}> = ({ apiRoute, user }) => { +}> = ({ user }) => { const { openModal } = useModal() const { t } = useTranslation() + const { + config: { + routes: { api: apiRoute }, + }, + } = useConfig() const handleResetPreferences = useCallback(async () => { if (!user) { @@ -36,10 +47,9 @@ export const ResetPreferences: React.FC<{ try { const res = await fetch( - formatApiURL({ + formatAdminURL({ apiRoute, path: `/payload-preferences${stringifiedQuery}`, - serverURL: undefined, }), { credentials: 'include', diff --git a/packages/next/src/views/Account/Settings/index.tsx b/packages/next/src/views/Account/Settings/index.tsx index b0396f23c5a..555d8d6e752 100644 --- a/packages/next/src/views/Account/Settings/index.tsx +++ b/packages/next/src/views/Account/Settings/index.tsx @@ -19,9 +19,7 @@ export const Settings: React.FC<{ readonly theme: Config['admin']['theme'] readonly user?: TypedUser }> = (props) => { - const { className, i18n, languageOptions, payload, theme, user } = props - - const apiRoute = payload.config.routes.api + const { className, i18n, languageOptions, theme, user } = props return (
@@ -31,7 +29,7 @@ export const Settings: React.FC<{
{theme === 'all' && } - +
) } diff --git a/packages/next/src/views/Account/index.tsx b/packages/next/src/views/Account/index.tsx index 7bb0ab89a6d..6e67398575e 100644 --- a/packages/next/src/views/Account/index.tsx +++ b/packages/next/src/views/Account/index.tsx @@ -4,6 +4,7 @@ import { DocumentInfoProvider, EditDepthProvider, HydrateAuthProvider } from '@p import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent' import { buildFormState } from '@payloadcms/ui/utilities/buildFormState' import { notFound } from 'next/navigation.js' +import { formatAdminURL } from 'payload/shared' import React from 'react' import { DocumentHeader } from '../../elements/DocumentHeader/index.js' @@ -116,7 +117,10 @@ export async function AccountView({ initPageResult, params, searchParams }: Admi user={user} /> } - apiURL={`${serverURL}${api}/${userSlug}${user?.id ? `/${user.id}` : ''}`} + apiURL={formatAdminURL({ + apiRoute: api, + path: `/${userSlug}${user?.id ? `/${user.id}` : ''}`, + })} collectionSlug={userSlug} currentEditor={currentEditor} docPermissions={docPermissions} diff --git a/packages/next/src/views/BrowseByFolder/buildView.tsx b/packages/next/src/views/BrowseByFolder/buildView.tsx index 59775ad7d31..af77f638659 100644 --- a/packages/next/src/views/BrowseByFolder/buildView.tsx +++ b/packages/next/src/views/BrowseByFolder/buildView.tsx @@ -143,7 +143,6 @@ export const buildBrowseByFolderView = async ( formatAdminURL({ adminRoute, path: config.admin.routes.browseByFolder, - serverURL: config.serverURL, }), ) } diff --git a/packages/next/src/views/CollectionFolders/buildView.tsx b/packages/next/src/views/CollectionFolders/buildView.tsx index 2d2384b7193..9edb76f319e 100644 --- a/packages/next/src/views/CollectionFolders/buildView.tsx +++ b/packages/next/src/views/CollectionFolders/buildView.tsx @@ -131,7 +131,6 @@ export const buildCollectionFolderView = async ( formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}/${config.folders.slug}`, - serverURL: config.serverURL, }), ) } diff --git a/packages/next/src/views/CreateFirstUser/index.client.tsx b/packages/next/src/views/CreateFirstUser/index.client.tsx index 4fa18ca60a0..f0c25c03537 100644 --- a/packages/next/src/views/CreateFirstUser/index.client.tsx +++ b/packages/next/src/views/CreateFirstUser/index.client.tsx @@ -20,7 +20,7 @@ import { useTranslation, } from '@payloadcms/ui' import { abortAndIgnore, handleAbortRef } from '@payloadcms/ui/shared' -import { formatApiURL } from 'payload/shared' +import { formatAdminURL } from 'payload/shared' import React, { useEffect } from 'react' export const CreateFirstUserClient: React.FC<{ @@ -33,7 +33,6 @@ export const CreateFirstUserClient: React.FC<{ const { config: { routes: { admin, api: apiRoute }, - serverURL, }, getEntityConfig, } = useConfig() @@ -85,10 +84,9 @@ export const CreateFirstUserClient: React.FC<{ return (
@@ -67,7 +65,6 @@ export function ForgotPasswordView({ initPageResult }: AdminViewServerProps) { href={formatAdminURL({ adminRoute, path: loginRoute, - serverURL, })} prefetch={false} > diff --git a/packages/next/src/views/List/index.tsx b/packages/next/src/views/List/index.tsx index 13f3d9172b1..8a6ae2dc3ef 100644 --- a/packages/next/src/views/List/index.tsx +++ b/packages/next/src/views/List/index.tsx @@ -346,7 +346,6 @@ export const renderListView = async ( const newDocumentURL = formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}/create`, - serverURL: config.serverURL, }) const hasCreatePermission = permissions?.collections?.[collectionSlug]?.create diff --git a/packages/next/src/views/Login/LoginForm/index.tsx b/packages/next/src/views/Login/LoginForm/index.tsx index 0f23805047c..04b045048b5 100644 --- a/packages/next/src/views/Login/LoginForm/index.tsx +++ b/packages/next/src/views/Login/LoginForm/index.tsx @@ -16,7 +16,7 @@ import { useConfig, useTranslation, } from '@payloadcms/ui' -import { formatAdminURL, formatApiURL, getLoginOptions, getSafeRedirect } from 'payload/shared' +import { formatAdminURL, getLoginOptions, getSafeRedirect } from 'payload/shared' import type { LoginFieldProps } from '../LoginField/index.js' @@ -86,10 +86,9 @@ export const LoginForm: React.FC<{ return ( diff --git a/packages/next/src/views/Logout/LogoutClient.tsx b/packages/next/src/views/Logout/LogoutClient.tsx index a1f1be5dead..212f1b47d5a 100644 --- a/packages/next/src/views/Logout/LogoutClient.tsx +++ b/packages/next/src/views/Logout/LogoutClient.tsx @@ -52,7 +52,6 @@ export const LogoutClient: React.FC<{ ? `?redirect=${encodeURIComponent(redirect)}` : '' }`, - serverURL: config.serverURL, }), ) diff --git a/packages/next/src/views/ResetPassword/ResetPasswordForm/index.tsx b/packages/next/src/views/ResetPassword/ResetPasswordForm/index.tsx index ee8d379f47a..d8aee4e8e20 100644 --- a/packages/next/src/views/ResetPassword/ResetPasswordForm/index.tsx +++ b/packages/next/src/views/ResetPassword/ResetPasswordForm/index.tsx @@ -11,7 +11,7 @@ import { } from '@payloadcms/ui' import { useRouter } from 'next/navigation.js' import { type FormState } from 'payload' -import { formatAdminURL, formatApiURL } from 'payload/shared' +import { formatAdminURL } from 'payload/shared' import React from 'react' type Args = { @@ -43,11 +43,10 @@ export const ResetPasswordForm: React.FC = ({ token }) => { formatAdminURL({ adminRoute, path: loginRoute, - serverURL, }), ) } - }, [adminRoute, fetchFullUser, history, loginRoute, serverURL]) + }, [adminRoute, fetchFullUser, history, loginRoute]) const initialState: FormState = { 'confirm-password': { @@ -69,10 +68,9 @@ export const ResetPasswordForm: React.FC = ({ token }) => { return ( @@ -72,7 +71,6 @@ export function ResetPassword({ initPageResult, params }: AdminViewServerProps) href={formatAdminURL({ adminRoute, path: loginRoute, - serverURL: config.serverURL, })} prefetch={false} > diff --git a/packages/next/src/views/Root/getRouteData.ts b/packages/next/src/views/Root/getRouteData.ts index 77be06d89e8..3a04aeca73f 100644 --- a/packages/next/src/views/Root/getRouteData.ts +++ b/packages/next/src/views/Root/getRouteData.ts @@ -163,8 +163,6 @@ export const getRouteData = ({ path: formatAdminURL({ adminRoute, path: route, - relative: true, - serverURL: config.serverURL, }), }) }) diff --git a/packages/next/src/views/Root/index.tsx b/packages/next/src/views/Root/index.tsx index d56b5282d57..e5514486fa1 100644 --- a/packages/next/src/views/Root/index.tsx +++ b/packages/next/src/views/Root/index.tsx @@ -63,12 +63,9 @@ export const RootPage = async ({ const params = await paramsPromise - // Intentionally omit `serverURL` to ensure relative path const currentRoute = formatAdminURL({ adminRoute, path: Array.isArray(params.segments) ? `/${params.segments.join('/')}` : null, - relative: true, - serverURL: config.serverURL, }) const segments = Array.isArray(params.segments) ? params.segments : [] @@ -229,8 +226,6 @@ export const RootPage = async ({ const createFirstUserRoute = formatAdminURL({ adminRoute, path: _createFirstUserRoute, - relative: true, - serverURL: config.serverURL, }) if (disableLocalStrategy && currentRoute === createFirstUserRoute) { @@ -255,6 +250,7 @@ export const RootPage = async ({ importMap, user: viewType === 'createFirstUser' ? true : req.user, }) + await applyLocaleFiltering({ clientConfig, config, req }) // Ensure locale on req is still valid after filtering locales diff --git a/packages/next/src/views/Unauthorized/index.tsx b/packages/next/src/views/Unauthorized/index.tsx index 75e2da2f588..bc5678c43c5 100644 --- a/packages/next/src/views/Unauthorized/index.tsx +++ b/packages/next/src/views/Unauthorized/index.tsx @@ -20,7 +20,6 @@ export function UnauthorizedView({ initPageResult }: AdminViewServerProps) { routes: { logout: logoutRoute }, }, routes: { admin: adminRoute }, - serverURL, }, }, user, @@ -42,7 +41,6 @@ export function UnauthorizedView({ initPageResult }: AdminViewServerProps) { to={formatAdminURL({ adminRoute, path: logoutRoute, - serverURL, })} > {i18n.t('authentication:logOut')} diff --git a/packages/next/src/views/Verify/index.tsx b/packages/next/src/views/Verify/index.tsx index 87475e007b5..b71245b97d2 100644 --- a/packages/next/src/views/Verify/index.tsx +++ b/packages/next/src/views/Verify/index.tsx @@ -46,7 +46,7 @@ export async function Verify({ initPageResult, params, searchParams }: AdminView return ( ) } diff --git a/packages/next/src/views/Version/Default/SetStepNav.tsx b/packages/next/src/views/Version/Default/SetStepNav.tsx index e94e91c702d..b74f7a1be6a 100644 --- a/packages/next/src/views/Version/Default/SetStepNav.tsx +++ b/packages/next/src/views/Version/Default/SetStepNav.tsx @@ -50,7 +50,6 @@ export const SetStepNav: React.FC<{ url: formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}`, - serverURL, }), }, ] @@ -61,7 +60,6 @@ export const SetStepNav: React.FC<{ url: formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}/trash`, - serverURL, }), }) } @@ -72,7 +70,6 @@ export const SetStepNav: React.FC<{ url: formatAdminURL({ adminRoute, path: docBasePath, - serverURL, }), }, { @@ -80,7 +77,6 @@ export const SetStepNav: React.FC<{ url: formatAdminURL({ adminRoute, path: `${docBasePath}/versions`, - serverURL, }), }, { @@ -102,7 +98,6 @@ export const SetStepNav: React.FC<{ url: formatAdminURL({ adminRoute, path: `/globals/${globalSlug}`, - serverURL, }), }, { @@ -110,7 +105,6 @@ export const SetStepNav: React.FC<{ url: formatAdminURL({ adminRoute, path: `/globals/${globalSlug}/versions`, - serverURL, }), }, { diff --git a/packages/next/src/views/Version/Restore/index.tsx b/packages/next/src/views/Version/Restore/index.tsx index 45c11f622cc..434031f19ba 100644 --- a/packages/next/src/views/Version/Restore/index.tsx +++ b/packages/next/src/views/Version/Restore/index.tsx @@ -66,7 +66,10 @@ export const Restore: React.FC = ({ const canRestoreAsDraft = status !== 'draft' && collectionConfig?.versions?.drafts const handleRestore = useCallback(async () => { - let fetchURL = `${serverURL}${apiRoute}` + let fetchURL = formatAdminURL({ + apiRoute, + path: '', + }) let redirectURL: string if (collectionConfig) { @@ -74,7 +77,6 @@ export const Restore: React.FC = ({ redirectURL = formatAdminURL({ adminRoute, path: `/collections/${collectionConfig.slug}/${originalDocID}`, - serverURL, }) } @@ -83,7 +85,6 @@ export const Restore: React.FC = ({ redirectURL = formatAdminURL({ adminRoute, path: `/globals/${globalConfig.slug}`, - serverURL, }) } @@ -101,7 +102,6 @@ export const Restore: React.FC = ({ toast.error(t('version:problemRestoringVersion')) } }, [ - serverURL, apiRoute, collectionConfig, globalConfig, diff --git a/packages/next/src/views/Versions/cells/CreatedAt/index.tsx b/packages/next/src/views/Versions/cells/CreatedAt/index.tsx index 6be93092ef6..15abcd988fe 100644 --- a/packages/next/src/views/Versions/cells/CreatedAt/index.tsx +++ b/packages/next/src/views/Versions/cells/CreatedAt/index.tsx @@ -26,7 +26,6 @@ export const CreatedAtCell: React.FC = ({ config: { admin: { dateFormat }, routes: { admin: adminRoute }, - serverURL, }, } = useConfig() @@ -40,7 +39,6 @@ export const CreatedAtCell: React.FC = ({ to = formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}/${trashedDocPrefix}${docID}/versions/${id}`, - serverURL, }) } @@ -48,7 +46,6 @@ export const CreatedAtCell: React.FC = ({ to = formatAdminURL({ adminRoute, path: `/globals/${globalSlug}/versions/${id}`, - serverURL, }) } diff --git a/packages/next/src/views/Versions/index.tsx b/packages/next/src/views/Versions/index.tsx index 064acc2c0a4..affd6abd369 100644 --- a/packages/next/src/views/Versions/index.tsx +++ b/packages/next/src/views/Versions/index.tsx @@ -1,7 +1,7 @@ import { Gutter, ListQueryProvider, SetDocumentStepNav } from '@payloadcms/ui' import { notFound } from 'next/navigation.js' import { type DocumentViewServerProps, type PaginatedDocs, type Where } from 'payload' -import { formatApiURL, hasDraftsEnabled, isNumber } from 'payload/shared' +import { formatAdminURL, hasDraftsEnabled, isNumber } from 'payload/shared' import React from 'react' import { fetchLatestVersion, fetchVersions } from '../Version/fetchVersions.js' @@ -115,10 +115,9 @@ export async function VersionsView(props: DocumentViewServerProps) { : Promise.resolve(null), ]) - const fetchURL = formatApiURL({ + const fetchURL = formatAdminURL({ apiRoute, path: collectionSlug ? `/${collectionSlug}/versions` : `/${globalSlug}/versions`, - serverURL, }) const columns = buildVersionColumns({ diff --git a/packages/payload/src/auth/sendVerificationEmail.ts b/packages/payload/src/auth/sendVerificationEmail.ts index 3734f879443..ede0597b861 100644 --- a/packages/payload/src/auth/sendVerificationEmail.ts +++ b/packages/payload/src/auth/sendVerificationEmail.ts @@ -7,6 +7,8 @@ import type { TypedUser } from '../index.js' import type { PayloadRequest } from '../types/index.js' import type { VerifyConfig } from './types.js' +import { formatAdminURL } from '../utilities/formatAdminURL.js' + type Args = { collection: Collection config: SanitizedConfig @@ -36,7 +38,11 @@ export async function sendVerificationEmail(args: Args): Promise { ? config.serverURL : `${protocol}//${req.headers.get('host')}` - const verificationURL = `${serverURL}${config.routes.admin}/${collectionConfig.slug}/verify/${token}` + const verificationURL = formatAdminURL({ + adminRoute: config.routes.admin, + path: `/${collectionConfig.slug}/verify/${token}`, + serverURL, + }) let html = `${req.t('authentication:newAccountCreated', { serverURL: config.serverURL, diff --git a/packages/payload/src/config/defaults.ts b/packages/payload/src/config/defaults.ts index b8493fc708f..c4312e009f7 100644 --- a/packages/payload/src/config/defaults.ts +++ b/packages/payload/src/config/defaults.ts @@ -150,7 +150,7 @@ export const addDefaultsToConfig = (config: Config): Config => { config.maxDepth = config.maxDepth ?? 10 config.routes = { admin: '/admin', - api: (process.env.NEXT_BASE_PATH ?? '') + '/api', + api: '/api', graphQL: '/graphql', graphQLPlayground: '/graphql-playground', ...(config.routes || {}), diff --git a/packages/payload/src/exports/shared.ts b/packages/payload/src/exports/shared.ts index a93deeb1fee..d5174c5532d 100644 --- a/packages/payload/src/exports/shared.ts +++ b/packages/payload/src/exports/shared.ts @@ -83,7 +83,6 @@ export { flattenAllFields } from '../utilities/flattenAllFields.js' export { flattenTopLevelFields } from '../utilities/flattenTopLevelFields.js' export { formatAdminURL } from '../utilities/formatAdminURL.js' -export { formatApiURL } from '../utilities/formatApiURL.js' export { formatLabels, toWords } from '../utilities/formatLabels.js' export { getBestFitFromSizes } from '../utilities/getBestFitFromSizes.js' diff --git a/packages/payload/src/index.ts b/packages/payload/src/index.ts index 2f15a70d753..93af68c321c 100644 --- a/packages/payload/src/index.ts +++ b/packages/payload/src/index.ts @@ -140,6 +140,7 @@ import { consoleEmailAdapter } from './email/consoleEmailAdapter.js' import { fieldAffectsData, type FlattenedBlock } from './fields/config/types.js' import { getJobsLocalAPI } from './queues/localAPI.js' import { _internal_jobSystemGlobals } from './queues/utilities/getCurrentDate.js' +import { formatAdminURL } from './utilities/formatAdminURL.js' import { isNextBuild } from './utilities/isNextBuild.js' import { getLogger } from './utilities/logger.js' import { serverInit as serverInitTelemetry } from './utilities/telemetry/events/serverInit.js' @@ -547,9 +548,19 @@ export class BasePayload { return forgotPasswordLocal(this, options) } - getAdminURL = (): string => `${this.config.serverURL}${this.config.routes.admin}` + getAdminURL = (): string => + formatAdminURL({ + adminRoute: this.config.routes.admin, + path: '', + serverURL: this.config.serverURL, + }) - getAPIURL = (): string => `${this.config.serverURL}${this.config.routes.api}` + getAPIURL = (): string => + formatAdminURL({ + apiRoute: this.config.routes.api, + path: '', + serverURL: this.config.serverURL, + }) globals!: Globals diff --git a/packages/payload/src/uploads/getBaseFields.ts b/packages/payload/src/uploads/getBaseFields.ts index 443ef91d2c0..581b86d625d 100644 --- a/packages/payload/src/uploads/getBaseFields.ts +++ b/packages/payload/src/uploads/getBaseFields.ts @@ -3,6 +3,7 @@ import type { Config } from '../config/types.js' import type { Field } from '../fields/config/types.js' import type { UploadConfig } from './types.js' +import { formatAdminURL } from '../utilities/formatAdminURL.js' import { mimeTypeValidator } from './mimeTypeValidator.js' type GenerateURLArgs = { @@ -12,7 +13,11 @@ type GenerateURLArgs = { } const generateURL = ({ collectionSlug, config, filename }: GenerateURLArgs) => { if (filename) { - return `${config.serverURL || ''}${config.routes?.api || ''}/${collectionSlug}/file/${encodeURIComponent(filename)}` + return formatAdminURL({ + apiRoute: config.routes?.api || '', + path: `/${collectionSlug}/file/${encodeURIComponent(filename)}`, + serverURL: config.serverURL, + }) } return undefined } @@ -223,7 +228,11 @@ export const getBaseUploadFields = ({ collection, config }: Options): Field[] => const sizeFilename = data?.sizes?.[size.name]?.filename if (sizeFilename) { - return `${config.serverURL}${config.routes?.api}/${collection.slug}/file/${encodeURIComponent(sizeFilename)}` + return formatAdminURL({ + apiRoute: config.routes?.api || '', + path: `/${collection.slug}/file/${encodeURIComponent(sizeFilename)}`, + serverURL: config.serverURL, + }) } return null diff --git a/packages/payload/src/utilities/createPayloadRequest.ts b/packages/payload/src/utilities/createPayloadRequest.ts index 6b27c41cb81..1bded5d44c8 100644 --- a/packages/payload/src/utilities/createPayloadRequest.ts +++ b/packages/payload/src/utilities/createPayloadRequest.ts @@ -9,6 +9,7 @@ import { executeAuthStrategies } from '../auth/executeAuthStrategies.js' import { getDataLoader } from '../collections/dataloader.js' import { getPayload } from '../index.js' import { sanitizeLocales } from './addLocalesToRequest.js' +import { formatAdminURL } from './formatAdminURL.js' import { getRequestLanguage } from './getRequestLanguage.js' import { parseCookies } from './parseCookies.js' @@ -43,7 +44,12 @@ export const createPayloadRequest = async ({ const { pathname, searchParams } = urlProperties const isGraphQL = - !config.graphQL.disable && pathname === `${config.routes.api}${config.routes.graphQL}` + !config.graphQL.disable && + pathname === + formatAdminURL({ + apiRoute: config.routes.api, + path: config.routes.graphQL as `/${string}`, + }) const language = getRequestLanguage({ config, diff --git a/packages/payload/src/utilities/formatAdminURL.spec.ts b/packages/payload/src/utilities/formatAdminURL.spec.ts index 8e592239fc8..73079df39db 100644 --- a/packages/payload/src/utilities/formatAdminURL.spec.ts +++ b/packages/payload/src/utilities/formatAdminURL.spec.ts @@ -39,7 +39,9 @@ describe('formatAdminURL', () => { serverURL, }) - expect(result).toBe(`${serverURL}${defaultAdminRoute}${dummyPath}`) + expect(result).toBe( + `${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}${dummyPath}`, + ) }) it('should handle serverURL with trailing slash', () => { @@ -49,7 +51,9 @@ describe('formatAdminURL', () => { serverURL: 'https://example.com/', }) - expect(result).toBe('https://example.com/admin/collections/posts') + expect(result).toBe( + `https://example.com${process.env.NEXT_BASE_PATH || ''}/admin/collections/posts`, + ) }) it('should handle serverURL with subdirectory', () => { @@ -59,7 +63,9 @@ describe('formatAdminURL', () => { serverURL: 'https://example.com/api/v1', }) - expect(result).toBe('https://example.com/admin/collections/posts') + expect(result).toBe( + `https://example.com${process.env.NEXT_BASE_PATH || ''}/admin/collections/posts`, + ) }) }) @@ -67,7 +73,6 @@ describe('formatAdminURL', () => { it('should return relative URL for adminRoute="/", no path, no `serverURL`', () => { const result = formatAdminURL({ adminRoute: rootAdminRoute, - relative: true, }) expect(result).toBe('/') @@ -77,7 +82,6 @@ describe('formatAdminURL', () => { const result = formatAdminURL({ adminRoute: rootAdminRoute, path: dummyPath, - relative: true, }) expect(result).toBe(dummyPath) @@ -99,7 +103,7 @@ describe('formatAdminURL', () => { path: dummyPath, }) - expect(result).toBe(`${serverURL}${dummyPath}`) + expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${dummyPath}`) }) }) @@ -112,7 +116,9 @@ describe('formatAdminURL', () => { serverURL, }) - expect(result).toBe(`${serverURL}/v1${defaultAdminRoute}${dummyPath}`) + expect(result).toBe( + `${serverURL}${process.env.NEXT_BASE_PATH || ''}/v1${defaultAdminRoute}${dummyPath}`, + ) }) it('should handle basePath with adminRoute="/"', () => { @@ -122,7 +128,7 @@ describe('formatAdminURL', () => { serverURL, }) - expect(result).toBe(`${serverURL}/v1`) + expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}/v1`) }) it('should handle basePath with no adminRoute', () => { @@ -133,7 +139,7 @@ describe('formatAdminURL', () => { serverURL, }) - expect(result).toBe(`${serverURL}/v1${dummyPath}`) + expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}/v1${dummyPath}`) }) it('should handle empty basePath', () => { @@ -144,7 +150,9 @@ describe('formatAdminURL', () => { serverURL, }) - expect(result).toBe(`${serverURL}${defaultAdminRoute}${dummyPath}`) + expect(result).toBe( + `${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}${dummyPath}`, + ) }) }) @@ -156,7 +164,7 @@ describe('formatAdminURL', () => { serverURL, }) - expect(result).toBe(`${serverURL}${defaultAdminRoute}`) + expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}`) }) it('should handle null path', () => { @@ -165,7 +173,7 @@ describe('formatAdminURL', () => { path: null, serverURL, }) - expect(result).toBe(`${serverURL}${defaultAdminRoute}`) + expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}`) }) it('should handle undefined path', () => { @@ -175,7 +183,7 @@ describe('formatAdminURL', () => { serverURL, }) - expect(result).toBe(`${serverURL}${defaultAdminRoute}`) + expect(result).toBe(`${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}`) }) it('should handle path with query parameters', () => { @@ -187,7 +195,9 @@ describe('formatAdminURL', () => { serverURL, }) - expect(result).toBe(`${serverURL}${defaultAdminRoute}${path}`) + expect(result).toBe( + `${serverURL}${process.env.NEXT_BASE_PATH || ''}${defaultAdminRoute}${path}`, + ) }) }) diff --git a/packages/payload/src/utilities/formatAdminURL.ts b/packages/payload/src/utilities/formatAdminURL.ts index 0becb74b1c4..ec42581fcb1 100644 --- a/packages/payload/src/utilities/formatAdminURL.ts +++ b/packages/payload/src/utilities/formatAdminURL.ts @@ -7,40 +7,55 @@ import type { Config } from '../config/types.js' * 2. Prepend the `basePath` from your Next.js config, if specified * 3. Return relative or absolute URLs, as needed */ -export const formatAdminURL = ( - args: { - adminRoute: NonNullable['admin'] - /** - * The subpath of your application, if specified. - * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/basePath - * @example '/docs' - */ - basePath?: string - path?: '' | `/${string}` | null - /** - * Return a relative URL, e.g. ignore `serverURL`. - * Useful for route-matching, etc. - */ - relative?: boolean - } & Pick, -): string => { - const { adminRoute, basePath = '', path = '', relative = false, serverURL } = args +type BaseFormatURLArgs = { + /** + * The subpath of your application, if specified. + * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/basePath + * @example '/docs' + */ + basePath?: string + includeBasePath?: boolean + path?: '' | `/${string}` | null + /** + * Return a relative URL, e.g. ignore `serverURL`. + * Useful for route-matching, etc. + */ + relative?: boolean +} & Pick - const pathSegments = [basePath] +type FormatURLArgs = + | ({ + adminRoute: NonNullable['admin'] + apiRoute?: never + } & BaseFormatURLArgs) + | ({ + adminRoute?: never + apiRoute: NonNullable['api'] + } & BaseFormatURLArgs) - if (adminRoute && adminRoute !== '/') { - pathSegments.push(adminRoute) - } - - if (path && !(adminRoute === '/' && !path)) { - pathSegments.push(path) - } - - const pathname = pathSegments.join('') || '/' +export const formatAdminURL = (args: FormatURLArgs): string => { + const { + adminRoute, + apiRoute, + includeBasePath: includeBasePathArg, + path = '', + relative = false, + serverURL, + } = args + const basePath = process.env.NEXT_BASE_PATH || args.basePath || '' + const routePath = adminRoute || apiRoute + const segments = [routePath && routePath !== '/' && routePath, path && path].filter(Boolean) + const pathname = segments.join('') || '/' + const pathnameWithBase = (basePath + pathname).replace(/\/$/, '') || '/' + const includeBasePath = includeBasePathArg ?? (adminRoute ? false : true) if (relative || !serverURL) { + if (includeBasePath && basePath) { + return pathnameWithBase + } return pathname } - return new URL(pathname, serverURL).toString() + const serverURLObj = new URL(serverURL) + return new URL(pathnameWithBase, serverURLObj.origin).toString() } diff --git a/packages/payload/src/utilities/formatApiURL.ts b/packages/payload/src/utilities/formatApiURL.ts deleted file mode 100644 index e01d25a6860..00000000000 --- a/packages/payload/src/utilities/formatApiURL.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Config } from '../config/types.js' - -import { formatAdminURL } from './formatAdminURL.js' - -/** Will read the `routes.api` config and appropriately handle `"/"` api paths */ -export const formatApiURL = (args: { - apiRoute: NonNullable['api'] - basePath?: string - path: '' | `/${string}` | null | undefined - serverURL: Config['serverURL'] -}): string => { - return formatAdminURL({ - adminRoute: args.apiRoute, - basePath: args.basePath, - path: args.path, - serverURL: args.serverURL, - }) -} diff --git a/packages/payload/src/utilities/handleEndpoints.ts b/packages/payload/src/utilities/handleEndpoints.ts index 9b1ef447a09..e53569db7c7 100644 --- a/packages/payload/src/utilities/handleEndpoints.ts +++ b/packages/payload/src/utilities/handleEndpoints.ts @@ -8,6 +8,7 @@ import type { GlobalConfig } from '../globals/config/types.js' import type { PayloadRequest } from '../types/index.js' import { createPayloadRequest } from './createPayloadRequest.js' +import { formatAdminURL } from './formatAdminURL.js' import { headersWithCors } from './headersWithCors.js' import { mergeHeaders } from './mergeHeaders.js' import { routeError } from './routeError.js' @@ -155,14 +156,18 @@ export const handleEndpoints = async ({ const { payload } = req const { config } = payload - const pathname = `${basePath}${path ?? new URL(req.url!).pathname}` + const pathname = path ?? new URL(req.url!).pathname + const baseAPIPath = formatAdminURL({ + apiRoute: config.routes.api, + path: '', + }) - if (!pathname.startsWith(config.routes.api)) { + if (!pathname.startsWith(baseAPIPath)) { return notFoundResponse(req, pathname) } // /api/posts/route -> /posts/route - let adjustedPathname = pathname.replace(config.routes.api, '') + let adjustedPathname = pathname.replace(baseAPIPath, '') let isGlobals = false diff --git a/packages/plugin-cloud-storage/src/client/createClientUploadHandler.tsx b/packages/plugin-cloud-storage/src/client/createClientUploadHandler.tsx index 0aab613fe00..4f2ef48a8e8 100644 --- a/packages/plugin-cloud-storage/src/client/createClientUploadHandler.tsx +++ b/packages/plugin-cloud-storage/src/client/createClientUploadHandler.tsx @@ -11,7 +11,7 @@ type ClientUploadHandlerProps> = { enabled?: boolean extra: T prefix?: string - serverHandlerPath: string + serverHandlerPath: `/${string}` } export const createClientUploadHandler = >({ @@ -23,7 +23,7 @@ export const createClientUploadHandler = >({ extra: T file: File prefix?: string - serverHandlerPath: string + serverHandlerPath: `/${string}` serverURL: string updateFilename: (value: string) => void }) => Promise diff --git a/packages/plugin-ecommerce/src/react/provider/index.tsx b/packages/plugin-ecommerce/src/react/provider/index.tsx index 6b7372ad175..3d0653b3f4c 100644 --- a/packages/plugin-ecommerce/src/react/provider/index.tsx +++ b/packages/plugin-ecommerce/src/react/provider/index.tsx @@ -1,7 +1,7 @@ 'use client' import type { DefaultDocumentIDType, TypedUser } from 'payload' -import { deepMergeSimple } from 'payload/shared' +import { deepMergeSimple, formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React, { createContext, @@ -96,8 +96,11 @@ export const EcommerceProvider: React.FC = ({ } : defaultLocalStorage - const { apiRoute = '/api', cartsFetchQuery = {}, serverURL = '' } = api || {} - const baseAPIURL = `${serverURL}${apiRoute}` + const { apiRoute = '/api', cartsFetchQuery = {} } = api || {} + const baseAPIURL = formatAdminURL({ + apiRoute, + path: '', + }) const [isLoading, startTransition] = useTransition() diff --git a/packages/plugin-import-export/src/components/ExportSaveButton/index.tsx b/packages/plugin-import-export/src/components/ExportSaveButton/index.tsx index 67aa84644eb..83583ccb4c6 100644 --- a/packages/plugin-import-export/src/components/ExportSaveButton/index.tsx +++ b/packages/plugin-import-export/src/components/ExportSaveButton/index.tsx @@ -10,6 +10,7 @@ import { useFormModified, useTranslation, } from '@payloadcms/ui' +import { formatAdminURL } from 'payload/shared' import React from 'react' import type { @@ -22,7 +23,6 @@ export const ExportSaveButton: React.FC = () => { const { config: { routes: { api }, - serverURL, }, getEntityConfig, } = useConfig() @@ -51,16 +51,22 @@ export const ExportSaveButton: React.FC = () => { toastID = toast.success('Your export is being processed...') }, 200) - const response = await fetch(`${serverURL}${api}/exports/download`, { - body: JSON.stringify({ - data, + const response = await fetch( + formatAdminURL({ + apiRoute: api, + path: '/exports/download', }), - credentials: 'include', - headers: { - 'Content-Type': 'application/json', + { + body: JSON.stringify({ + data, + }), + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', }, - method: 'POST', - }) + ) // Clear the timeout if fetch completes quickly if (timeoutID) { diff --git a/packages/plugin-multi-tenant/src/providers/TenantSelectionProvider/index.client.tsx b/packages/plugin-multi-tenant/src/providers/TenantSelectionProvider/index.client.tsx index aa76a0b0adf..793b1c731ec 100644 --- a/packages/plugin-multi-tenant/src/providers/TenantSelectionProvider/index.client.tsx +++ b/packages/plugin-multi-tenant/src/providers/TenantSelectionProvider/index.client.tsx @@ -4,6 +4,7 @@ import type { OptionObject } from 'payload' import { toast, useAuth, useConfig } from '@payloadcms/ui' import { useRouter } from 'next/navigation.js' +import { formatAdminURL } from 'payload/shared' import React, { createContext } from 'react' import { generateCookie } from '../../utilities/generateCookie.js' @@ -171,7 +172,10 @@ export const TenantSelectionProviderClient = ({ const syncTenants = React.useCallback(async () => { try { const req = await fetch( - `${config.serverURL}${config.routes.api}/${tenantsCollectionSlug}/populate-tenant-options`, + formatAdminURL({ + apiRoute: config.routes.api, + path: `/${tenantsCollectionSlug}/populate-tenant-options`, + }), { credentials: 'include', method: 'GET', @@ -191,7 +195,7 @@ export const TenantSelectionProviderClient = ({ } catch (e) { toast.error(`Error fetching tenants`) } - }, [config.serverURL, config.routes.api, tenantsCollectionSlug, userID]) + }, [config.routes.api, tenantsCollectionSlug, userID]) const updateTenants = React.useCallback( ({ id, label }) => { diff --git a/packages/plugin-multi-tenant/src/utilities/getGlobalViewRedirect.ts b/packages/plugin-multi-tenant/src/utilities/getGlobalViewRedirect.ts index 515a9dc9cba..8b93135f6a8 100644 --- a/packages/plugin-multi-tenant/src/utilities/getGlobalViewRedirect.ts +++ b/packages/plugin-multi-tenant/src/utilities/getGlobalViewRedirect.ts @@ -10,6 +10,11 @@ import { getTenantFromCookie } from './getTenantFromCookie.js' import { getTenantOptions } from './getTenantOptions.js' type Args = { + /** + * This is no longer needed and is handled internally. + * + * @deprecated + */ basePath?: string docID?: number | string headers: Headers @@ -26,7 +31,6 @@ type Args = { } export async function getGlobalViewRedirect({ slug: collectionSlug, - basePath, docID, headers, payload, @@ -121,7 +125,6 @@ export async function getGlobalViewRedirect({ // no tenants were found, redirect to the admin view return formatAdminURL({ adminRoute: payload.config.routes.admin, - basePath, path: '', serverURL: payload.config.serverURL, }) @@ -130,7 +133,6 @@ export async function getGlobalViewRedirect({ if (redirectRoute) { return formatAdminURL({ adminRoute: payload.config.routes.admin, - basePath, path: redirectRoute, serverURL: payload.config.serverURL, }) diff --git a/packages/plugin-search/src/Search/ui/LinkToDoc/index.client.tsx b/packages/plugin-search/src/Search/ui/LinkToDoc/index.client.tsx index 28c57538843..6c3ccd25cd8 100644 --- a/packages/plugin-search/src/Search/ui/LinkToDoc/index.client.tsx +++ b/packages/plugin-search/src/Search/ui/LinkToDoc/index.client.tsx @@ -20,13 +20,11 @@ export const LinkToDocClient: React.FC = () => { return null } - const href = `${serverURL}${formatAdminURL({ + const href = formatAdminURL({ adminRoute, path: `/collections/${value.relationTo || ''}/${value.value || ''}`, serverURL, - })}` - - const hrefToDisplay = `${process.env.NEXT_BASE_PATH || ''}${href}` + }) return (
@@ -39,7 +37,7 @@ export const LinkToDocClient: React.FC = () => { > Doc URL - +
{ }} > - {hrefToDisplay} + {href}
diff --git a/packages/plugin-search/src/Search/ui/ReindexButton/index.client.tsx b/packages/plugin-search/src/Search/ui/ReindexButton/index.client.tsx index 2c4f1a9d7c6..bb1d256789e 100644 --- a/packages/plugin-search/src/Search/ui/ReindexButton/index.client.tsx +++ b/packages/plugin-search/src/Search/ui/ReindexButton/index.client.tsx @@ -11,6 +11,7 @@ import { useTranslation, } from '@payloadcms/ui' import { useRouter } from 'next/navigation.js' +import { formatAdminURL } from 'payload/shared' import React, { useCallback, useMemo, useState } from 'react' import type { ReindexButtonProps } from './types.js' @@ -45,12 +46,18 @@ export const ReindexButtonClient: React.FC = ({ } try { - const res = await fetch(`${config.routes.api}/${searchSlug}/reindex?locale=${locale.code}`, { - body: JSON.stringify({ - collections: reindexCollections, + const res = await fetch( + formatAdminURL({ + apiRoute: config.routes.api, + path: `/${searchSlug}/reindex?locale=${locale.code}`, }), - method: 'POST', - }) + { + body: JSON.stringify({ + collections: reindexCollections, + }), + method: 'POST', + }, + ) const { message } = (await res.json()) as { message: string } diff --git a/packages/plugin-seo/src/fields/MetaDescription/MetaDescriptionComponent.tsx b/packages/plugin-seo/src/fields/MetaDescription/MetaDescriptionComponent.tsx index dab8f3f1761..a48c66585d0 100644 --- a/packages/plugin-seo/src/fields/MetaDescription/MetaDescriptionComponent.tsx +++ b/packages/plugin-seo/src/fields/MetaDescription/MetaDescriptionComponent.tsx @@ -15,6 +15,7 @@ import { useTranslation, } from '@payloadcms/ui' import { reduceToSerializableFields } from '@payloadcms/ui/shared' +import { formatAdminURL } from 'payload/shared' import React, { useCallback } from 'react' import type { PluginSEOTranslationKeys, PluginSEOTranslations } from '../../translations/index.js' @@ -45,7 +46,6 @@ export const MetaDescriptionComponent: React.FC = (props) const { config: { routes: { api }, - serverURL, }, } = useConfig() @@ -73,7 +73,10 @@ export const MetaDescriptionComponent: React.FC = (props) return } - const endpoint = `${serverURL}${api}/plugin-seo/generate-description` + const endpoint = formatAdminURL({ + apiRoute: api, + path: '/plugin-seo/generate-description', + }) const genDescriptionResponse = await fetch(endpoint, { body: JSON.stringify({ @@ -104,7 +107,7 @@ export const MetaDescriptionComponent: React.FC = (props) setValue(generatedDescription || '') }, [ hasGenerateDescriptionFn, - serverURL, + api, docInfo.id, docInfo.collectionSlug, diff --git a/packages/plugin-seo/src/fields/MetaImage/MetaImageComponent.tsx b/packages/plugin-seo/src/fields/MetaImage/MetaImageComponent.tsx index 86cdcaccc27..58fb8dbc5bb 100644 --- a/packages/plugin-seo/src/fields/MetaImage/MetaImageComponent.tsx +++ b/packages/plugin-seo/src/fields/MetaImage/MetaImageComponent.tsx @@ -16,6 +16,7 @@ import { useTranslation, } from '@payloadcms/ui' import { reduceToSerializableFields } from '@payloadcms/ui/shared' +import { formatAdminURL } from 'payload/shared' import React, { useCallback } from 'react' import type { PluginSEOTranslationKeys, PluginSEOTranslations } from '../../translations/index.js' @@ -64,7 +65,10 @@ export const MetaImageComponent: React.FC = (props) => { return } - const endpoint = `${serverURL}${api}/plugin-seo/generate-image` + const endpoint = formatAdminURL({ + apiRoute: api, + path: '/plugin-seo/generate-image', + }) const genImageResponse = await fetch(endpoint, { body: JSON.stringify({ @@ -103,7 +107,6 @@ export const MetaImageComponent: React.FC = (props) => { setValue(newValue || '') }, [ hasGenerateImageFn, - serverURL, api, docInfo.id, docInfo.collectionSlug, diff --git a/packages/plugin-seo/src/fields/MetaTitle/MetaTitleComponent.tsx b/packages/plugin-seo/src/fields/MetaTitle/MetaTitleComponent.tsx index 5ba712609a3..76e416666f4 100644 --- a/packages/plugin-seo/src/fields/MetaTitle/MetaTitleComponent.tsx +++ b/packages/plugin-seo/src/fields/MetaTitle/MetaTitleComponent.tsx @@ -15,6 +15,7 @@ import { useTranslation, } from '@payloadcms/ui' import { reduceToSerializableFields } from '@payloadcms/ui/shared' +import { formatAdminURL } from 'payload/shared' import React, { useCallback } from 'react' import type { PluginSEOTranslationKeys, PluginSEOTranslations } from '../../translations/index.js' @@ -48,7 +49,6 @@ export const MetaTitleComponent: React.FC = (props) => { const { config: { routes: { api }, - serverURL, }, } = useConfig() @@ -74,7 +74,10 @@ export const MetaTitleComponent: React.FC = (props) => { return } - const endpoint = `${serverURL}${api}/plugin-seo/generate-title` + const endpoint = formatAdminURL({ + apiRoute: api, + path: '/plugin-seo/generate-title', + }) const genTitleResponse = await fetch(endpoint, { body: JSON.stringify({ @@ -105,7 +108,6 @@ export const MetaTitleComponent: React.FC = (props) => { setValue(generatedTitle || '') }, [ hasGenerateTitleFn, - serverURL, api, docInfo.id, docInfo.collectionSlug, diff --git a/packages/plugin-seo/src/fields/Preview/PreviewComponent.tsx b/packages/plugin-seo/src/fields/Preview/PreviewComponent.tsx index c7d7db2efbd..59c81963021 100644 --- a/packages/plugin-seo/src/fields/Preview/PreviewComponent.tsx +++ b/packages/plugin-seo/src/fields/Preview/PreviewComponent.tsx @@ -12,6 +12,7 @@ import { useTranslation, } from '@payloadcms/ui' import { reduceToSerializableFields } from '@payloadcms/ui/shared' +import { formatAdminURL } from 'payload/shared' import React, { useEffect, useState } from 'react' import type { PluginSEOTranslationKeys, PluginSEOTranslations } from '../../translations/index.js' @@ -35,7 +36,6 @@ export const PreviewComponent: React.FC = (props) => { const { config: { routes: { api }, - serverURL, }, } = useConfig() @@ -56,7 +56,10 @@ export const PreviewComponent: React.FC = (props) => { const [href, setHref] = useState() useEffect(() => { - const endpoint = `${serverURL}${api}/plugin-seo/generate-url` + const endpoint = formatAdminURL({ + apiRoute: api, + path: '/plugin-seo/generate-url', + }) const getHref = async () => { const genURLResponse = await fetch(endpoint, { @@ -91,7 +94,7 @@ export const PreviewComponent: React.FC = (props) => { if (hasGenerateURLFn && !href) { void getHref() } - }, [fields, href, locale, docInfo, hasGenerateURLFn, getData, serverURL, api, title]) + }, [fields, href, locale, docInfo, hasGenerateURLFn, getData, api, title]) return (
{ if (!res.ok) { throw new Error(`HTTP error! Status: ${res.status}`) diff --git a/packages/richtext-lexical/src/features/relationship/client/components/RelationshipComponent.tsx b/packages/richtext-lexical/src/features/relationship/client/components/RelationshipComponent.tsx index ab05115b24d..9c3f8e5c2f1 100644 --- a/packages/richtext-lexical/src/features/relationship/client/components/RelationshipComponent.tsx +++ b/packages/richtext-lexical/src/features/relationship/client/components/RelationshipComponent.tsx @@ -6,12 +6,13 @@ import { useLexicalEditable } from '@lexical/react/useLexicalEditable' import { getTranslation } from '@payloadcms/translations' import { Button, useConfig, usePayloadAPI, useTranslation } from '@payloadcms/ui' import { $getNodeByKey } from 'lexical' +import { formatAdminURL } from 'payload/shared' import React, { useCallback, useReducer, useRef, useState } from 'react' import type { RelationshipData } from '../../server/nodes/RelationshipNode.js' -import { useLexicalDocumentDrawer } from '../../../../utilities/fieldsDrawer/useLexicalDocumentDrawer.js' import './index.scss' +import { useLexicalDocumentDrawer } from '../../../../utilities/fieldsDrawer/useLexicalDocumentDrawer.js' import { INSERT_RELATIONSHIP_WITH_DRAWER_COMMAND } from '../drawer/commands.js' const initialParams = { @@ -55,7 +56,7 @@ export const RelationshipComponent: React.FC = (props) => { const { i18n, t } = useTranslation() const [cacheBust, dispatchCacheBust] = useReducer((state) => state + 1, 0) const [{ data }, { setParams }] = usePayloadAPI( - `${serverURL}${api}/${relatedCollection.slug}/${value}`, + formatAdminURL({ apiRoute: api, path: `/${relatedCollection.slug}/${value}`, serverURL }), { initialParams }, ) diff --git a/packages/richtext-lexical/src/features/upload/client/component/index.tsx b/packages/richtext-lexical/src/features/upload/client/component/index.tsx index 30e8ca914da..b6df9a8d436 100644 --- a/packages/richtext-lexical/src/features/upload/client/component/index.tsx +++ b/packages/richtext-lexical/src/features/upload/client/component/index.tsx @@ -14,7 +14,7 @@ import { useTranslation, } from '@payloadcms/ui' import { $getNodeByKey, type ElementFormatType } from 'lexical' -import { isImage } from 'payload/shared' +import { formatAdminURL, isImage } from 'payload/shared' import React, { useCallback, useId, useReducer, useRef, useState } from 'react' import type { BaseClientFeatureProps } from '../../../typesClient.js' @@ -94,7 +94,7 @@ export const UploadComponent: React.FC = (props) => { // Get the referenced document const [{ data }, { setParams }] = usePayloadAPI( - `${serverURL}${api}/${relatedCollection.slug}/${value}`, + formatAdminURL({ apiRoute: api, path: `/${relatedCollection.slug}/${value}`, serverURL }), { initialParams }, ) diff --git a/packages/richtext-slate/src/field/elements/relationship/Element/index.tsx b/packages/richtext-slate/src/field/elements/relationship/Element/index.tsx index d31cb5e420b..f091ca43547 100644 --- a/packages/richtext-slate/src/field/elements/relationship/Element/index.tsx +++ b/packages/richtext-slate/src/field/elements/relationship/Element/index.tsx @@ -11,6 +11,7 @@ import { usePayloadAPI, useTranslation, } from '@payloadcms/ui' +import { formatAdminURL } from 'payload/shared' import React, { useCallback, useReducer, useState } from 'react' import { Transforms } from 'slate' import { ReactEditor, useFocused, useSelected, useSlateStatic } from 'slate-react' @@ -18,8 +19,8 @@ import { ReactEditor, useFocused, useSelected, useSlateStatic } from 'slate-reac import type { RelationshipElementType } from '../types.js' import { useElement } from '../../../providers/ElementProvider.js' -import { EnabledRelationshipsCondition } from '../../EnabledRelationshipsCondition.js' import './index.scss' +import { EnabledRelationshipsCondition } from '../../EnabledRelationshipsCondition.js' const baseClass = 'rich-text-relationship' @@ -59,7 +60,7 @@ const RelationshipElementComponent: React.FC = () => { const editor = useSlateStatic() const [cacheBust, dispatchCacheBust] = useReducer((state) => state + 1, 0) const [{ data }, { setParams }] = usePayloadAPI( - `${serverURL}${api}/${relatedCollection.slug}/${value?.id}`, + formatAdminURL({ apiRoute: api, path: `/${relatedCollection.slug}/${value?.id}`, serverURL }), { initialParams }, ) diff --git a/packages/richtext-slate/src/field/elements/upload/Element/index.tsx b/packages/richtext-slate/src/field/elements/upload/Element/index.tsx index 9f1d63b0df8..61623209b87 100644 --- a/packages/richtext-slate/src/field/elements/upload/Element/index.tsx +++ b/packages/richtext-slate/src/field/elements/upload/Element/index.tsx @@ -15,6 +15,7 @@ import { usePayloadAPI, useTranslation, } from '@payloadcms/ui' +import { formatAdminURL } from 'payload/shared' import React, { useCallback, useReducer, useState } from 'react' import { Transforms } from 'slate' import { ReactEditor, useFocused, useSelected, useSlateStatic } from 'slate-react' @@ -24,8 +25,8 @@ import type { UploadElementType } from '../types.js' import { useElement } from '../../../providers/ElementProvider.js' import { EnabledRelationshipsCondition } from '../../EnabledRelationshipsCondition.js' import { uploadFieldsSchemaPath, uploadName } from '../shared.js' -import { UploadDrawer } from './UploadDrawer/index.js' import './index.scss' +import { UploadDrawer } from './UploadDrawer/index.js' const baseClass = 'rich-text-upload' @@ -76,7 +77,7 @@ const UploadElementComponent: React.FC<{ enabledCollectionSlugs?: string[] }> = // Get the referenced document const [{ data }, { setParams }] = usePayloadAPI( - `${serverURL}${api}/${relatedCollection.slug}/${value?.id}`, + formatAdminURL({ apiRoute: api, path: `/${relatedCollection.slug}/${value?.id}`, serverURL }), { initialParams }, ) diff --git a/packages/storage-azure/src/client/AzureClientUploadHandler.ts b/packages/storage-azure/src/client/AzureClientUploadHandler.ts index 40cdb19e14f..766a07a478c 100644 --- a/packages/storage-azure/src/client/AzureClientUploadHandler.ts +++ b/packages/storage-azure/src/client/AzureClientUploadHandler.ts @@ -1,9 +1,15 @@ 'use client' import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client' +import { formatAdminURL } from 'payload/shared' export const AzureClientUploadHandler = createClientUploadHandler({ handler: async ({ apiRoute, collectionSlug, file, prefix, serverHandlerPath, serverURL }) => { - const response = await fetch(`${serverURL}${apiRoute}${serverHandlerPath}`, { + const endpointRoute = formatAdminURL({ + apiRoute, + path: serverHandlerPath, + serverURL, + }) + const response = await fetch(endpointRoute, { body: JSON.stringify({ collectionSlug, filename: file.name, diff --git a/packages/storage-gcs/src/client/GcsClientUploadHandler.ts b/packages/storage-gcs/src/client/GcsClientUploadHandler.ts index 47be23808d4..67b5607795e 100644 --- a/packages/storage-gcs/src/client/GcsClientUploadHandler.ts +++ b/packages/storage-gcs/src/client/GcsClientUploadHandler.ts @@ -1,9 +1,15 @@ 'use client' import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client' +import { formatAdminURL } from 'payload/shared' export const GcsClientUploadHandler = createClientUploadHandler({ handler: async ({ apiRoute, collectionSlug, file, prefix, serverHandlerPath, serverURL }) => { - const response = await fetch(`${serverURL}${apiRoute}${serverHandlerPath}`, { + const endpointRoute = formatAdminURL({ + apiRoute, + path: serverHandlerPath, + serverURL, + }) + const response = await fetch(endpointRoute, { body: JSON.stringify({ collectionSlug, filename: file.name, diff --git a/packages/storage-s3/src/client/S3ClientUploadHandler.ts b/packages/storage-s3/src/client/S3ClientUploadHandler.ts index 5424bc7b0cd..59935fb2975 100644 --- a/packages/storage-s3/src/client/S3ClientUploadHandler.ts +++ b/packages/storage-s3/src/client/S3ClientUploadHandler.ts @@ -1,9 +1,15 @@ 'use client' import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client' +import { formatAdminURL } from 'payload/shared' export const S3ClientUploadHandler = createClientUploadHandler({ handler: async ({ apiRoute, collectionSlug, file, prefix, serverHandlerPath, serverURL }) => { - const response = await fetch(`${serverURL}${apiRoute}${serverHandlerPath}`, { + const endpointRoute = formatAdminURL({ + apiRoute, + path: serverHandlerPath, + serverURL, + }) + const response = await fetch(endpointRoute, { body: JSON.stringify({ collectionSlug, filename: file.name, diff --git a/packages/storage-uploadthing/src/client/UploadthingClientUploadHandler.ts b/packages/storage-uploadthing/src/client/UploadthingClientUploadHandler.ts index c5b5a3a7e4b..74fd9c02729 100644 --- a/packages/storage-uploadthing/src/client/UploadthingClientUploadHandler.ts +++ b/packages/storage-uploadthing/src/client/UploadthingClientUploadHandler.ts @@ -1,12 +1,18 @@ 'use client' import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client' +import { formatAdminURL } from 'payload/shared' import { genUploader } from 'uploadthing/client' export const UploadthingClientUploadHandler = createClientUploadHandler({ handler: async ({ apiRoute, collectionSlug, file, serverHandlerPath, serverURL }) => { + const endpointRoute = formatAdminURL({ + apiRoute, + path: `${serverHandlerPath}?collectionSlug=${collectionSlug}`, + serverURL, + }) const { uploadFiles } = genUploader({ package: 'storage-uploadthing', - url: `${serverURL}${apiRoute}${serverHandlerPath}?collectionSlug=${collectionSlug}`, + url: endpointRoute, }) const res = await uploadFiles('uploader', { diff --git a/packages/storage-vercel-blob/src/client/VercelBlobClientUploadHandler.ts b/packages/storage-vercel-blob/src/client/VercelBlobClientUploadHandler.ts index 1edbac81e49..002939e1dfe 100644 --- a/packages/storage-vercel-blob/src/client/VercelBlobClientUploadHandler.ts +++ b/packages/storage-vercel-blob/src/client/VercelBlobClientUploadHandler.ts @@ -1,6 +1,7 @@ 'use client' import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client' import { upload } from '@vercel/blob/client' +import { formatAdminURL } from 'payload/shared' export type VercelBlobClientUploadHandlerExtra = { addRandomSuffix: boolean @@ -19,11 +20,16 @@ export const VercelBlobClientUploadHandler = serverURL, updateFilename, }) => { + const endpointRoute = formatAdminURL({ + apiRoute, + path: serverHandlerPath, + serverURL, + }) const result = await upload(`${prefix}${file.name}`, file, { access: 'public', clientPayload: collectionSlug, contentType: file.type, - handleUploadUrl: `${serverURL}${apiRoute}${serverHandlerPath}`, + handleUploadUrl: endpointRoute, }) // Update filename with suffix from returned url diff --git a/packages/ui/src/elements/AppHeader/index.tsx b/packages/ui/src/elements/AppHeader/index.tsx index fffa9016a2d..fe26323ad48 100644 --- a/packages/ui/src/elements/AppHeader/index.tsx +++ b/packages/ui/src/elements/AppHeader/index.tsx @@ -97,7 +97,7 @@ export function AppHeader({ CustomAvatar, CustomIcon }: Props) { diff --git a/packages/ui/src/elements/Autosave/index.tsx b/packages/ui/src/elements/Autosave/index.tsx index f54244055a6..12dc1255c69 100644 --- a/packages/ui/src/elements/Autosave/index.tsx +++ b/packages/ui/src/elements/Autosave/index.tsx @@ -4,10 +4,12 @@ import type { ClientCollectionConfig, ClientGlobalConfig } from 'payload' import { dequal } from 'dequal/lite' import { + formatAdminURL, getAutosaveInterval, hasDraftValidationEnabled, reduceFieldsToValues, } from 'payload/shared' +import * as qs from 'qs-esm' import React, { useDeferredValue, useEffect, useRef, useState } from 'react' import type { OnSaveContext } from '../../views/Edit/index.js' @@ -45,7 +47,6 @@ export const Autosave: React.FC = ({ id, collection, global: globalDoc }) const { config: { routes: { api }, - serverURL, }, } = useConfig() @@ -109,16 +110,34 @@ export const Autosave: React.FC = ({ id, collection, global: globalDoc }) let url: string let method: string let entitySlug: string + const queryParams = qs.stringify( + { + autosave: true, + depth: 0, + draft: true, + 'fallback-locale': 'null', + locale, + }, + { + addQueryPrefix: true, + }, + ) if (collection && id) { entitySlug = collection.slug - url = `${serverURL}${api}/${entitySlug}/${id}?depth=0&draft=true&autosave=true&locale=${locale}&fallback-locale=null` + url = formatAdminURL({ + apiRoute: api, + path: `/${entitySlug}/${id}${queryParams}`, + }) method = 'PATCH' } if (globalDoc) { entitySlug = globalDoc.slug - url = `${serverURL}${api}/globals/${entitySlug}?depth=0&draft=true&autosave=true&locale=${locale}&fallback-locale=null` + url = formatAdminURL({ + apiRoute: api, + path: `/globals/${entitySlug}${queryParams}`, + }) method = 'POST' } diff --git a/packages/ui/src/elements/BulkUpload/FormsManager/index.tsx b/packages/ui/src/elements/BulkUpload/FormsManager/index.tsx index f1461d174be..4709bb0dd94 100644 --- a/packages/ui/src/elements/BulkUpload/FormsManager/index.tsx +++ b/packages/ui/src/elements/BulkUpload/FormsManager/index.tsx @@ -11,6 +11,7 @@ import type { } from 'payload' import { useModal } from '@faceless-ui/modal' +import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React from 'react' import { toast } from 'sonner' @@ -103,7 +104,6 @@ export function FormsManagerProvider({ children }: FormsManagerProps) { const { config } = useConfig() const { routes: { api }, - serverURL, } = config const { code } = useLocale() const { i18n, t } = useTranslation() @@ -145,7 +145,12 @@ export function FormsManagerProvider({ children }: FormsManagerProps) { const initialStateRef = React.useRef(null) const getFormDataRef = React.useRef<() => Data>(() => ({})) - const actionURL = `${serverURL}${api}/${collectionSlug}` + const baseAPIPath = formatAdminURL({ + apiRoute: api, + path: '', + }) + + const actionURL = `${baseAPIPath}/${collectionSlug}` const initializeSharedDocPermissions = React.useCallback(async () => { const params = { @@ -153,7 +158,7 @@ export function FormsManagerProvider({ children }: FormsManagerProps) { } const docAccessURL = `/${collectionSlug}/access` - const res = await fetch(`${serverURL}${api}${docAccessURL}?${qs.stringify(params)}`, { + const res = await fetch(`${baseAPIPath}${docAccessURL}?${qs.stringify(params)}`, { credentials: 'include', headers: { 'Accept-Language': i18n.language, @@ -164,7 +169,7 @@ export function FormsManagerProvider({ children }: FormsManagerProps) { const json: SanitizedDocumentPermissions = await res.json() const publishedAccessJSON = await fetch( - `${serverURL}${api}${docAccessURL}?${qs.stringify(params)}`, + `${baseAPIPath}${docAccessURL}?${qs.stringify(params)}`, { body: JSON.stringify({ _status: 'published', @@ -190,7 +195,7 @@ export function FormsManagerProvider({ children }: FormsManagerProps) { setHasPublishPermission(publishedAccessJSON?.update) setHasInitializedDocPermissions(true) - }, [api, code, collectionSlug, i18n.language, serverURL]) + }, [baseAPIPath, code, collectionSlug, i18n.language]) const initializeSharedFormState = React.useCallback( async (abortController?: AbortController) => { diff --git a/packages/ui/src/elements/CopyLocaleData/index.tsx b/packages/ui/src/elements/CopyLocaleData/index.tsx index 22ba57bba64..8bd289f7fad 100644 --- a/packages/ui/src/elements/CopyLocaleData/index.tsx +++ b/packages/ui/src/elements/CopyLocaleData/index.tsx @@ -30,7 +30,6 @@ export const CopyLocaleData: React.FC = () => { config: { localization, routes: { admin }, - serverURL, }, } = useConfig() const { code } = useLocale() @@ -86,7 +85,6 @@ export const CopyLocaleData: React.FC = () => { formatAdminURL({ adminRoute: admin, path: `/${collectionSlug ? `collections/${collectionSlug}/${id}` : `globals/${globalSlug}`}`, - serverURL, }) + `?locale=${to}`, ), ) @@ -104,7 +102,6 @@ export const CopyLocaleData: React.FC = () => { overwriteExisting, toggleModal, router, - serverURL, admin, startRouteTransition, ], diff --git a/packages/ui/src/elements/DefaultListViewTabs/index.tsx b/packages/ui/src/elements/DefaultListViewTabs/index.tsx index f10b9e6a162..a363259c153 100644 --- a/packages/ui/src/elements/DefaultListViewTabs/index.tsx +++ b/packages/ui/src/elements/DefaultListViewTabs/index.tsx @@ -63,7 +63,6 @@ export const DefaultListViewTabs: React.FC = ({ const url = formatAdminURL({ adminRoute: config.routes.admin, path, - serverURL: config.serverURL, }) router.push(url) diff --git a/packages/ui/src/elements/DeleteDocument/index.tsx b/packages/ui/src/elements/DeleteDocument/index.tsx index 0424787375a..8c2d290ed41 100644 --- a/packages/ui/src/elements/DeleteDocument/index.tsx +++ b/packages/ui/src/elements/DeleteDocument/index.tsx @@ -49,7 +49,6 @@ export const DeleteDocument: React.FC = (props) => { const { config: { routes: { admin: adminRoute, api }, - serverURL, }, getEntityConfig, } = useConfig() @@ -75,15 +74,19 @@ export const DeleteDocument: React.FC = (props) => { setModified(false) try { + const url = formatAdminURL({ + apiRoute: api, + path: `/${collectionSlug}/${id}`, + }) const res = deletePermanently || !collectionConfig.trash - ? await requests.delete(`${serverURL}${api}/${collectionSlug}/${id}`, { + ? await requests.delete(url, { headers: { 'Accept-Language': i18n.language, 'Content-Type': 'application/json', }, }) - : await requests.patch(`${serverURL}${api}/${collectionSlug}/${id}`, { + : await requests.patch(url, { body: JSON.stringify({ deletedAt: new Date().toISOString(), }), @@ -110,9 +113,7 @@ export const DeleteDocument: React.FC = (props) => { if (redirectAfterDelete) { return startRouteTransition(() => - router.push( - formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}`, serverURL }), - ), + router.push(formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}` })), ) } @@ -136,7 +137,7 @@ export const DeleteDocument: React.FC = (props) => { }, [ deletePermanently, setModified, - serverURL, + api, collectionSlug, id, diff --git a/packages/ui/src/elements/DeleteMany/index.tsx b/packages/ui/src/elements/DeleteMany/index.tsx index 55727dbca0e..1c492a1682f 100644 --- a/packages/ui/src/elements/DeleteMany/index.tsx +++ b/packages/ui/src/elements/DeleteMany/index.tsx @@ -4,7 +4,7 @@ import type { ClientCollectionConfig, ViewTypes, Where } from 'payload' import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' import { useRouter, useSearchParams } from 'next/navigation.js' -import { mergeListSearchAndWhere } from 'payload/shared' +import { formatAdminURL, mergeListSearchAndWhere } from 'payload/shared' import * as qs from 'qs-esm' import React from 'react' import { toast } from 'sonner' @@ -226,20 +226,23 @@ export function DeleteMany_v4({ } } - const url = `${serverURL}${api}/${relationTo}${qs.stringify( - { - limit: 0, - locale, - select: {}, - where: mergeListSearchAndWhere({ - collectionConfig, - search, - where: whereConstraint, - }), - ...(viewType === 'trash' ? { trash: true } : {}), - }, - { addQueryPrefix: true }, - )}` + const url = formatAdminURL({ + apiRoute: api, + path: `/${relationTo}${qs.stringify( + { + limit: 0, + locale, + select: {}, + where: mergeListSearchAndWhere({ + collectionConfig, + search, + where: whereConstraint, + }), + ...(viewType === 'trash' ? { trash: true } : {}), + }, + { addQueryPrefix: true }, + )}`, + }) const deleteManyResponse = viewType === 'trash' || deletePermanently || !collectionConfig.trash diff --git a/packages/ui/src/elements/DocumentControls/index.tsx b/packages/ui/src/elements/DocumentControls/index.tsx index 484891353c7..c572ba7fc82 100644 --- a/packages/ui/src/elements/DocumentControls/index.tsx +++ b/packages/ui/src/elements/DocumentControls/index.tsx @@ -352,7 +352,6 @@ export const DocumentControls: React.FC<{ href={formatAdminURL({ adminRoute, path: `/collections/${collectionConfig?.slug}/create`, - serverURL, })} id="action-create" > diff --git a/packages/ui/src/elements/DuplicateDocument/index.tsx b/packages/ui/src/elements/DuplicateDocument/index.tsx index d2c09fafbd4..554016faaa1 100644 --- a/packages/ui/src/elements/DuplicateDocument/index.tsx +++ b/packages/ui/src/elements/DuplicateDocument/index.tsx @@ -5,7 +5,7 @@ import type { SanitizedCollectionConfig } from 'payload' import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' import { useRouter } from 'next/navigation.js' -import { formatAdminURL, formatApiURL, hasDraftsEnabled } from 'payload/shared' +import { formatAdminURL, hasDraftsEnabled } from 'payload/shared' import * as qs from 'qs-esm' import React, { useCallback, useMemo } from 'react' import { toast } from 'sonner' @@ -91,12 +91,11 @@ export const DuplicateDocument: React.FC = ({ try { const res = await requests.post( - formatApiURL({ + formatAdminURL({ apiRoute, path: `/${slug}/${id}/duplicate${qs.stringify(queryParams, { addQueryPrefix: true, })}`, - serverURL, }), { body: JSON.stringify(hasDraftsEnabled(collectionConfig) ? { _status: 'draft' } : {}), @@ -120,7 +119,6 @@ export const DuplicateDocument: React.FC = ({ formatAdminURL({ adminRoute, path: `/collections/${slug}/${doc.id}${localeCode ? `?locale=${localeCode}` : ''}`, - serverURL, }), ), ) diff --git a/packages/ui/src/elements/EditMany/DrawerContent.tsx b/packages/ui/src/elements/EditMany/DrawerContent.tsx index ef59956f347..1d36c7e5ae7 100644 --- a/packages/ui/src/elements/EditMany/DrawerContent.tsx +++ b/packages/ui/src/elements/EditMany/DrawerContent.tsx @@ -7,7 +7,7 @@ import { getTranslation } from '@payloadcms/translations' import { useRouter, useSearchParams } from 'next/navigation.js' import { combineWhereConstraints, - formatApiURL, + formatAdminURL, mergeListSearchAndWhere, unflatten, } from 'payload/shared' @@ -169,7 +169,6 @@ export const EditManyDrawerContent: React.FC = (prop const { config: { routes: { api: apiRoute }, - serverURL, }, } = useConfig() @@ -390,28 +389,25 @@ export const EditManyDrawerContent: React.FC = (prop {collection?.versions?.drafts ? ( ) : ( diff --git a/packages/ui/src/elements/FolderView/BrowseByFolderButton/index.tsx b/packages/ui/src/elements/FolderView/BrowseByFolderButton/index.tsx index 4add306a50a..18f9b1a5bc1 100644 --- a/packages/ui/src/elements/FolderView/BrowseByFolderButton/index.tsx +++ b/packages/ui/src/elements/FolderView/BrowseByFolderButton/index.tsx @@ -17,7 +17,6 @@ export function BrowseByFolderButton({ active }) { routes: { browseByFolder: foldersRoute }, }, routes: { admin: adminRoute }, - serverURL, } = config return ( @@ -26,7 +25,6 @@ export function BrowseByFolderButton({ active }) { href={formatAdminURL({ adminRoute, path: foldersRoute, - serverURL, })} id="browse-by-folder" prefetch={false} diff --git a/packages/ui/src/elements/FolderView/Cell/index.client.tsx b/packages/ui/src/elements/FolderView/Cell/index.client.tsx index fb3151e0a07..a0655b7de5c 100644 --- a/packages/ui/src/elements/FolderView/Cell/index.client.tsx +++ b/packages/ui/src/elements/FolderView/Cell/index.client.tsx @@ -3,6 +3,7 @@ import type { Data, ViewTypes } from 'payload' import type { FolderOrDocument } from 'payload/shared' +import { formatAdminURL } from 'payload/shared' import React, { useEffect } from 'react' // eslint-disable-next-line payload/no-imports-from-exports-dir @@ -40,16 +41,22 @@ export const FolderTableCellClient = ({ const onConfirm = React.useCallback( async ({ id, name }) => { try { - await fetch(`${config.routes.api}/${collectionSlug}/${docID}`, { - body: JSON.stringify({ - [folderFieldName]: id, + await fetch( + formatAdminURL({ + apiRoute: config.routes.api, + path: `/${collectionSlug}/${docID}`, }), - credentials: 'include', - headers: { - 'Content-Type': 'application/json', + { + body: JSON.stringify({ + [folderFieldName]: id, + }), + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + }, + method: 'PATCH', }, - method: 'PATCH', - }) + ) setFromFolderID(id) setFromFolderName(name || t('folder:noFolder')) @@ -65,7 +72,10 @@ export const FolderTableCellClient = ({ const loadFolderName = async () => { try { const req = await fetch( - `${config.routes.api}/${folderCollectionSlug}${intialFolderID ? `/${intialFolderID}` : ''}`, + formatAdminURL({ + apiRoute: config.routes.api, + path: `/${folderCollectionSlug}${intialFolderID ? `/${intialFolderID}` : ''}`, + }), { credentials: 'include', headers: { diff --git a/packages/ui/src/elements/FolderView/CurrentFolderActions/index.tsx b/packages/ui/src/elements/FolderView/CurrentFolderActions/index.tsx index d0d54ecf00c..cc77bd85335 100644 --- a/packages/ui/src/elements/FolderView/CurrentFolderActions/index.tsx +++ b/packages/ui/src/elements/FolderView/CurrentFolderActions/index.tsx @@ -1,6 +1,7 @@ import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' import { useRouter } from 'next/navigation.js' +import { formatAdminURL } from 'payload/shared' import React from 'react' import { toast } from 'sonner' @@ -44,15 +45,21 @@ export function CurrentFolderActions({ className }: Props) { }) const { clearRouteCache } = useRouteCache() const { config } = useConfig() - const { routes, serverURL } = config + const { routes } = config const { closeModal, openModal } = useModal() const { i18n, t } = useTranslation() const deleteCurrentFolder = React.useCallback(async () => { - await fetch(`${serverURL}${routes.api}/${folderCollectionSlug}/${folderID}?depth=0`, { - credentials: 'include', - method: 'DELETE', - }) + await fetch( + formatAdminURL({ + apiRoute: routes.api, + path: `/${folderCollectionSlug}/${folderID}?depth=0`, + }), + { + credentials: 'include', + method: 'DELETE', + }, + ) startRouteTransition(() => { router.push(getFolderRoute(breadcrumbs[breadcrumbs.length - 2]?.id || null)) }) @@ -62,7 +69,6 @@ export function CurrentFolderActions({ className }: Props) { folderID, getFolderRoute, router, - serverURL, routes.api, startRouteTransition, ]) diff --git a/packages/ui/src/elements/FolderView/MoveDocToFolder/index.tsx b/packages/ui/src/elements/FolderView/MoveDocToFolder/index.tsx index 2493c04f577..08b997c1156 100644 --- a/packages/ui/src/elements/FolderView/MoveDocToFolder/index.tsx +++ b/packages/ui/src/elements/FolderView/MoveDocToFolder/index.tsx @@ -1,10 +1,8 @@ 'use client' -import type { CollectionSlug } from 'payload' -import type { FolderOrDocument } from 'payload/shared' - import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' +import { type FolderOrDocument, formatAdminURL } from 'payload/shared' import React, { useId } from 'react' import { toast } from 'sonner' @@ -52,7 +50,12 @@ export function MoveDocToFolder({ React.useEffect(() => { async function fetchFolderLabel() { if (fromFolderID && (typeof fromFolderID === 'string' || typeof fromFolderID === 'number')) { - const response = await fetch(`${config.routes.api}/${folderCollectionSlug}/${fromFolderID}`) + const response = await fetch( + formatAdminURL({ + apiRoute: config.routes.api, + path: `/${folderCollectionSlug}/${fromFolderID}`, + }), + ) const folderData = await response.json() setFromFolderName(folderData?.name || t('folder:noFolder')) } else { diff --git a/packages/ui/src/elements/IDLabel/index.tsx b/packages/ui/src/elements/IDLabel/index.tsx index ba3bacc71c9..4315c06e0ec 100644 --- a/packages/ui/src/elements/IDLabel/index.tsx +++ b/packages/ui/src/elements/IDLabel/index.tsx @@ -19,7 +19,6 @@ export const IDLabel: React.FC<{ className?: string; id: string; prefix?: string const { config: { routes: { admin: adminRoute }, - serverURL, }, } = useConfig() @@ -29,7 +28,6 @@ export const IDLabel: React.FC<{ className?: string; id: string; prefix?: string const docPath = formatAdminURL({ adminRoute, path: `/${collectionSlug ? `collections/${collectionSlug}` : `globals/${globalSlug}`}/${id}`, - serverURL, }) return ( diff --git a/packages/ui/src/elements/ListHeader/TitleActions/ListEmptyTrashButton.tsx b/packages/ui/src/elements/ListHeader/TitleActions/ListEmptyTrashButton.tsx index a3cbf05d538..ffd23f208f1 100644 --- a/packages/ui/src/elements/ListHeader/TitleActions/ListEmptyTrashButton.tsx +++ b/packages/ui/src/elements/ListHeader/TitleActions/ListEmptyTrashButton.tsx @@ -4,6 +4,7 @@ import type { ClientCollectionConfig } from 'payload' import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' import { useRouter, useSearchParams } from 'next/navigation.js' +import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React from 'react' import { toast } from 'sonner' @@ -55,7 +56,10 @@ export function ListEmptyTrashButton({ try { const res = await requests.get( - `${config.serverURL}${config.routes.api}/${collectionConfig.slug}${queryString}`, + formatAdminURL({ + apiRoute: config.routes.api, + path: `/${collectionConfig.slug}${queryString}`, + }), { headers: { 'Accept-Language': i18n.language, @@ -96,7 +100,10 @@ export function ListEmptyTrashButton({ ) const res = await requests.delete( - `${config.serverURL}${config.routes.api}/${slug}${queryString}`, + formatAdminURL({ + apiRoute: config.routes.api, + path: `/${slug}${queryString}`, + }), { headers: { 'Accept-Language': i18n.language, diff --git a/packages/ui/src/elements/Logout/index.tsx b/packages/ui/src/elements/Logout/index.tsx index e7005cdac63..182fd7a1cb8 100644 --- a/packages/ui/src/elements/Logout/index.tsx +++ b/packages/ui/src/elements/Logout/index.tsx @@ -26,7 +26,6 @@ export const Logout: React.FC<{ routes: { logout: logoutRoute }, }, routes: { admin: adminRoute }, - serverURL, } = config return ( @@ -36,7 +35,6 @@ export const Logout: React.FC<{ href={formatAdminURL({ adminRoute, path: logoutRoute, - serverURL, })} prefetch={false} tabIndex={tabIndex} diff --git a/packages/ui/src/elements/PermanentlyDeleteButton/index.tsx b/packages/ui/src/elements/PermanentlyDeleteButton/index.tsx index 23a6da10fd0..a5446d38717 100644 --- a/packages/ui/src/elements/PermanentlyDeleteButton/index.tsx +++ b/packages/ui/src/elements/PermanentlyDeleteButton/index.tsx @@ -65,12 +65,20 @@ export const PermanentlyDeleteButton: React.FC = (props) => { const handleDelete = useCallback(async () => { try { - const url = `${serverURL}${api}/${collectionSlug}?${qs.stringify({ - trash: true, - where: { - and: [{ id: { equals: id } }, { deletedAt: { exists: true } }], - }, - })}` + const url = formatAdminURL({ + apiRoute: api, + path: `/${collectionSlug}${qs.stringify( + { + trash: true, + where: { + and: [{ id: { equals: id } }, { deletedAt: { exists: true } }], + }, + }, + { + addQueryPrefix: true, + }, + )}`, + }) const res = await requests.delete(url, { headers: { diff --git a/packages/ui/src/elements/PublishButton/ScheduleDrawer/index.tsx b/packages/ui/src/elements/PublishButton/ScheduleDrawer/index.tsx index 7f140b0b9c1..4ed783b73c6 100644 --- a/packages/ui/src/elements/PublishButton/ScheduleDrawer/index.tsx +++ b/packages/ui/src/elements/PublishButton/ScheduleDrawer/index.tsx @@ -8,6 +8,7 @@ import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' import { endOfToday, isToday, startOfDay } from 'date-fns' import { transpose } from 'date-fns/transpose' +import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React, { useCallback, useMemo } from 'react' import { toast } from 'sonner' @@ -28,8 +29,8 @@ import { Button } from '../../Button/index.js' import { DatePickerField } from '../../DatePicker/index.js' import { Drawer } from '../../Drawer/index.js' import { Gutter } from '../../Gutter/index.js' -import { ReactSelect } from '../../ReactSelect/index.js' import './index.scss' +import { ReactSelect } from '../../ReactSelect/index.js' import { ShimmerEffect } from '../../ShimmerEffect/index.js' import { Table } from '../../Table/index.js' import { TimezonePicker } from '../../TimezonePicker/index.js' @@ -134,7 +135,7 @@ export const ScheduleDrawer: React.FC = ({ slug, defaultType, schedulePub } const { docs } = await requests - .post(`${serverURL}${api}/payload-jobs`, { + .post(formatAdminURL({ apiRoute: api, path: `/payload-jobs` }), { body: qs.stringify(query), headers: { 'Accept-Language': i18n.language, diff --git a/packages/ui/src/elements/PublishButton/index.tsx b/packages/ui/src/elements/PublishButton/index.tsx index 7ee3928a4b9..c0f8467eee3 100644 --- a/packages/ui/src/elements/PublishButton/index.tsx +++ b/packages/ui/src/elements/PublishButton/index.tsx @@ -4,7 +4,7 @@ import type { PublishButtonClientProps } from 'payload' import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' -import { hasAutosaveEnabled, hasScheduledPublishEnabled } from 'payload/shared' +import { formatAdminURL, hasAutosaveEnabled, hasScheduledPublishEnabled } from 'payload/shared' import * as qs from 'qs-esm' import React, { useCallback, useEffect, useState } from 'react' @@ -105,14 +105,20 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { let method = 'POST' if (collectionSlug) { - action = `${serverURL}${api}/${collectionSlug}${id ? `/${id}` : ''}${search}` + action = formatAdminURL({ + apiRoute: api, + path: `/${collectionSlug}${id ? `/${id}` : ''}${search}`, + }) if (id) { method = 'PATCH' } } if (globalSlug) { - action = `${serverURL}${api}/globals/${globalSlug}${search}` + action = formatAdminURL({ + apiRoute: api, + path: `/globals/${globalSlug}${search}`, + }) } await submit({ @@ -169,9 +175,13 @@ export function PublishButton({ label: labelProp }: PublishButtonClientProps) { publishSpecificLocale: locale, }) - const action = `${serverURL}${api}${ - globalSlug ? `/globals/${globalSlug}` : `/${collectionSlug}${id ? `/${id}` : ''}` - }${params ? '?' + params : ''}` + const pathSegment = globalSlug + ? `/globals/${globalSlug}` + : `/${collectionSlug}${id ? `/${id}` : ''}` + const action = formatAdminURL({ + apiRoute: api, + path: `${pathSegment}${params ? '?' + params : ''}` as `/${string}`, + }) const result = await submit({ action, diff --git a/packages/ui/src/elements/PublishMany/DrawerContent.tsx b/packages/ui/src/elements/PublishMany/DrawerContent.tsx index beb81a44b08..4a4ae911ddc 100644 --- a/packages/ui/src/elements/PublishMany/DrawerContent.tsx +++ b/packages/ui/src/elements/PublishMany/DrawerContent.tsx @@ -2,7 +2,7 @@ import type { Where } from 'payload' import { getTranslation } from '@payloadcms/translations' import { useRouter, useSearchParams } from 'next/navigation.js' -import { combineWhereConstraints, mergeListSearchAndWhere } from 'payload/shared' +import { combineWhereConstraints, formatAdminURL, mergeListSearchAndWhere } from 'payload/shared' import * as qs from 'qs-esm' import React, { useCallback } from 'react' import { toast } from 'sonner' @@ -41,7 +41,6 @@ export function PublishManyDrawerContent(props: PublishManyDrawerContentProps) { const { config: { routes: { api }, - serverURL, }, } = useConfig() @@ -106,8 +105,12 @@ export function PublishManyDrawerContent(props: PublishManyDrawerContentProps) { }, [collection, searchParams, selectAll, ids, locale, where]) const handlePublish = useCallback(async () => { + const url = formatAdminURL({ + apiRoute: api, + path: `/${slug}${queryString}&draft=true`, + }) await requests - .patch(`${serverURL}${api}/${slug}${queryString}&draft=true`, { + .patch(url, { body: JSON.stringify({ _status: 'published', }), @@ -167,7 +170,6 @@ export function PublishManyDrawerContent(props: PublishManyDrawerContentProps) { } }) }, [ - serverURL, api, slug, queryString, diff --git a/packages/ui/src/elements/QueryPresets/QueryPresetBar/index.tsx b/packages/ui/src/elements/QueryPresets/QueryPresetBar/index.tsx index af5627da4f0..de1d2058c81 100644 --- a/packages/ui/src/elements/QueryPresets/QueryPresetBar/index.tsx +++ b/packages/ui/src/elements/QueryPresets/QueryPresetBar/index.tsx @@ -3,7 +3,7 @@ import type { QueryPreset, SanitizedCollectionPermission } from 'payload' import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' import { - formatApiURL, + formatAdminURL, transformColumnsToPreferences, transformColumnsToSearchParams, } from 'payload/shared' @@ -113,10 +113,9 @@ export const QueryPresetBar: React.FC<{ const handleDeletePreset = useCallback(async () => { try { await fetch( - formatApiURL({ + formatAdminURL({ apiRoute, path: `/${queryPresetsSlug}/${activePreset.id}`, - serverURL, }), { method: 'DELETE', @@ -148,24 +147,14 @@ export const QueryPresetBar: React.FC<{ } catch (_err) { toast.error(t('error:deletingTitle', { title: activePreset.title })) } - }, [ - apiRoute, - activePreset?.id, - activePreset?.title, - t, - presetConfig, - i18n, - resetQueryPreset, - serverURL, - ]) + }, [apiRoute, activePreset?.id, activePreset?.title, t, presetConfig, i18n, resetQueryPreset]) const saveCurrentChanges = useCallback(async () => { try { await fetch( - formatApiURL({ + formatAdminURL({ apiRoute, path: `/${queryPresetsSlug}/${activePreset.id}`, - serverURL, }), { body: JSON.stringify({ @@ -215,7 +204,6 @@ export const QueryPresetBar: React.FC<{ presetConfig?.labels?.singular, i18n, setQueryModified, - serverURL, ]) const hasModifiedPreset = activePreset && modified diff --git a/packages/ui/src/elements/RestoreButton/index.tsx b/packages/ui/src/elements/RestoreButton/index.tsx index 0b24f4c2cda..6f8fcfb36c9 100644 --- a/packages/ui/src/elements/RestoreButton/index.tsx +++ b/packages/ui/src/elements/RestoreButton/index.tsx @@ -71,12 +71,20 @@ export const RestoreButton: React.FC = (props) => { const handleRestore = useCallback(async () => { try { - const url = `${serverURL}${api}/${collectionSlug}?${qs.stringify({ - trash: true, - where: { - and: [{ id: { equals: id } }, { deletedAt: { exists: true } }], - }, - })}` + const url = formatAdminURL({ + apiRoute: api, + path: `/${collectionSlug}${qs.stringify( + { + trash: true, + where: { + and: [{ id: { equals: id } }, { deletedAt: { exists: true } }], + }, + }, + { + addQueryPrefix: true, + }, + )}`, + }) const body: Record = { deletedAt: null, diff --git a/packages/ui/src/elements/RestoreMany/index.tsx b/packages/ui/src/elements/RestoreMany/index.tsx index a427c6a1c60..38f48e13884 100644 --- a/packages/ui/src/elements/RestoreMany/index.tsx +++ b/packages/ui/src/elements/RestoreMany/index.tsx @@ -4,7 +4,7 @@ import type { ClientCollectionConfig, ViewTypes, Where } from 'payload' import { useModal } from '@faceless-ui/modal' import { getTranslation } from '@payloadcms/translations' import { useRouter, useSearchParams } from 'next/navigation.js' -import { mergeListSearchAndWhere } from 'payload/shared' +import { formatAdminURL, mergeListSearchAndWhere } from 'payload/shared' import * as qs from 'qs-esm' import React from 'react' import { toast } from 'sonner' @@ -84,20 +84,23 @@ export const RestoreMany: React.FC = (props) => { } } - const url = `${serverURL}${routes.api}/${slug}${qs.stringify( - { - limit: 0, - locale, - select: {}, - trash: true, // Ensure trashed docs are returned - where: mergeListSearchAndWhere({ - collectionConfig, - search: parseSearchParams(searchParams)?.search as string, - where: whereConstraint, - }), - }, - { addQueryPrefix: true }, - )}` + const url = formatAdminURL({ + apiRoute: routes.api, + path: `/${slug}${qs.stringify( + { + limit: 0, + locale, + select: {}, + trash: true, // Ensure trashed docs are returned + where: mergeListSearchAndWhere({ + collectionConfig, + search: parseSearchParams(searchParams)?.search as string, + where: whereConstraint, + }), + }, + { addQueryPrefix: true }, + )}`, + }) const body: Record = { deletedAt: null, diff --git a/packages/ui/src/elements/SaveDraftButton/index.tsx b/packages/ui/src/elements/SaveDraftButton/index.tsx index 71534bb330d..b958ac5c997 100644 --- a/packages/ui/src/elements/SaveDraftButton/index.tsx +++ b/packages/ui/src/elements/SaveDraftButton/index.tsx @@ -2,6 +2,7 @@ import type { SaveDraftButtonClientProps } from 'payload' +import { formatAdminURL } from 'payload/shared' import React, { useCallback, useRef } from 'react' import { useForm, useFormModified } from '../../forms/Form/context.js' @@ -20,7 +21,6 @@ export function SaveDraftButton(props: SaveDraftButtonClientProps) { const { config: { routes: { api }, - serverURL, }, } = useConfig() @@ -47,14 +47,20 @@ export function SaveDraftButton(props: SaveDraftButtonClientProps) { let method = 'POST' if (collectionSlug) { - action = `${serverURL}${api}/${collectionSlug}${id ? `/${id}` : ''}${search}` + action = formatAdminURL({ + apiRoute: api, + path: `/${collectionSlug}${id ? `/${id}` : ''}${search}`, + }) if (id) { method = 'PATCH' } } if (globalSlug) { - action = `${serverURL}${api}/globals/${globalSlug}${search}` + action = formatAdminURL({ + apiRoute: api, + path: `/globals/${globalSlug}${search}`, + }) } await submit({ @@ -67,17 +73,7 @@ export function SaveDraftButton(props: SaveDraftButtonClientProps) { }) setUnpublishedVersionCount((count) => count + 1) - }, [ - submit, - collectionSlug, - globalSlug, - serverURL, - api, - locale, - id, - disabled, - setUnpublishedVersionCount, - ]) + }, [submit, collectionSlug, globalSlug, api, locale, id, disabled, setUnpublishedVersionCount]) useHotkey({ cmdCtrlKey: true, editDepth, keyCodes: ['s'] }, (e) => { if (disabled) { diff --git a/packages/ui/src/elements/Status/index.tsx b/packages/ui/src/elements/Status/index.tsx index fc59f452bf1..85a01e5da57 100644 --- a/packages/ui/src/elements/Status/index.tsx +++ b/packages/ui/src/elements/Status/index.tsx @@ -1,5 +1,6 @@ 'use client' import { useModal } from '@faceless-ui/modal' +import { formatAdminURL } from 'payload/shared' import React, { useCallback } from 'react' import { toast } from 'sonner' @@ -35,7 +36,6 @@ export const Status: React.FC = () => { const { config: { routes: { api }, - serverURL, }, } = useConfig() @@ -75,12 +75,18 @@ export const Status: React.FC = () => { } if (collectionSlug) { - url = `${serverURL}${api}/${collectionSlug}/${id}?locale=${locale}&fallback-locale=null&depth=0` + url = formatAdminURL({ + apiRoute: api, + path: `/${collectionSlug}/${id}?locale=${locale}&fallback-locale=null&depth=0`, + }) method = 'patch' } if (globalSlug) { - url = `${serverURL}${api}/globals/${globalSlug}?locale=${locale}&fallback-locale=null&depth=0` + url = formatAdminURL({ + apiRoute: api, + path: `/globals/${globalSlug}?locale=${locale}&fallback-locale=null&depth=0`, + }) method = 'post' } @@ -151,7 +157,6 @@ export const Status: React.FC = () => { incrementVersionCount, locale, resetForm, - serverURL, setUnpublishedVersionCount, setMostRecentVersionIsAutosaved, t, @@ -190,29 +195,26 @@ export const Status: React.FC = () => { /> )} - {!isTrashed && - canUpdate && - hasPublishedDoc && - statusToRender === 'changed' && ( - -  —  - - performAction('revert')} - /> - - )} + {!isTrashed && canUpdate && hasPublishedDoc && statusToRender === 'changed' && ( + +  —  + + performAction('revert')} + /> + + )}
) diff --git a/packages/ui/src/elements/StayLoggedIn/index.tsx b/packages/ui/src/elements/StayLoggedIn/index.tsx index 40311708ebf..bd4b8c1b15c 100644 --- a/packages/ui/src/elements/StayLoggedIn/index.tsx +++ b/packages/ui/src/elements/StayLoggedIn/index.tsx @@ -24,7 +24,6 @@ export const StayLoggedInModal: React.FC = () => { routes: { logout: logoutRoute }, }, routes: { admin: adminRoute }, - serverURL, } = config const { t } = useTranslation() @@ -36,11 +35,10 @@ export const StayLoggedInModal: React.FC = () => { formatAdminURL({ adminRoute, path: logoutRoute, - serverURL, }), ), ) - }, [router, startRouteTransition, adminRoute, logoutRoute, serverURL]) + }, [router, startRouteTransition, adminRoute, logoutRoute]) const onCancel: OnCancel = useCallback(() => { refreshCookie() diff --git a/packages/ui/src/elements/Table/DefaultCell/fields/Relationship/index.tsx b/packages/ui/src/elements/Table/DefaultCell/fields/Relationship/index.tsx index 1986fb1a2fa..ae18b6d6a07 100644 --- a/packages/ui/src/elements/Table/DefaultCell/fields/Relationship/index.tsx +++ b/packages/ui/src/elements/Table/DefaultCell/fields/Relationship/index.tsx @@ -42,7 +42,7 @@ export const RelationshipCell: React.FC = ({ }, [cellDataFromProps, field]) const { config, getEntityConfig } = useConfig() - const { collections, routes } = config + const { collections } = config const [intersectionRef, entry] = useIntersect() const [values, setValues] = useState([]) const { documents, getRelationships } = useListRelationships() @@ -75,15 +75,7 @@ export const RelationshipCell: React.FC = ({ setHasRequested(true) setValues(formattedValues) } - }, [ - cellData, - relationTo, - collections, - isAboveViewport, - routes.api, - hasRequested, - getRelationships, - ]) + }, [cellData, relationTo, collections, isAboveViewport, hasRequested, getRelationships]) useEffect(() => { if (hasRequested) { diff --git a/packages/ui/src/elements/Table/DefaultCell/index.tsx b/packages/ui/src/elements/Table/DefaultCell/index.tsx index adc67c71ddd..56b40ccd7ca 100644 --- a/packages/ui/src/elements/Table/DefaultCell/index.tsx +++ b/packages/ui/src/elements/Table/DefaultCell/index.tsx @@ -33,7 +33,6 @@ export const DefaultCell: React.FC = (props) => { const { config: { routes: { admin: adminRoute }, - serverURL, }, getEntityConfig, } = useConfig() @@ -73,7 +72,6 @@ export const DefaultCell: React.FC = (props) => { ? formatAdminURL({ adminRoute, path: `/collections/${collectionConfig?.slug}${viewType === 'trash' ? '/trash' : ''}/${encodeURIComponent(rowData.id)}`, - serverURL, }) : '' } diff --git a/packages/ui/src/elements/Table/OrderableTable.tsx b/packages/ui/src/elements/Table/OrderableTable.tsx index e8125831652..1f3fddb2828 100644 --- a/packages/ui/src/elements/Table/OrderableTable.tsx +++ b/packages/ui/src/elements/Table/OrderableTable.tsx @@ -5,6 +5,7 @@ import type { ClientCollectionConfig, Column, OrderableEndpointBody } from 'payl import './index.scss' import { DragOverlay } from '@dnd-kit/core' +import { formatAdminURL } from 'payload/shared' import React, { useEffect, useState } from 'react' import { toast } from 'sonner' @@ -119,14 +120,20 @@ export const OrderableTable: React.FC = ({ target, } - const response = await fetch(`${config.serverURL}${config.routes.api}/reorder`, { - body: JSON.stringify(jsonBody), - credentials: 'include', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + formatAdminURL({ + apiRoute: config.routes.api, + path: '/reorder', + }), + { + body: JSON.stringify(jsonBody), + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + }, + method: 'POST', }, - method: 'POST', - }) + ) if (response.status === 403) { throw new Error('You do not have permission to reorder these rows') diff --git a/packages/ui/src/elements/Table/RelationshipProvider/index.tsx b/packages/ui/src/elements/Table/RelationshipProvider/index.tsx index b2ade8f4657..aa4fc6f58c3 100644 --- a/packages/ui/src/elements/Table/RelationshipProvider/index.tsx +++ b/packages/ui/src/elements/Table/RelationshipProvider/index.tsx @@ -1,7 +1,7 @@ 'use client' import type { SelectType, TypeWithID } from 'payload' -import { appendUploadSelectFields } from 'payload/shared' +import { appendUploadSelectFields, formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React, { createContext, use, useCallback, useEffect, useReducer, useRef } from 'react' @@ -42,7 +42,6 @@ export const RelationshipProvider: React.FC<{ readonly children?: React.ReactNod config: { collections, routes: { api }, - serverURL, }, } = useConfig() @@ -62,7 +61,7 @@ export const RelationshipProvider: React.FC<{ readonly children?: React.ReactNod }) if (idsToLoad.length > 0) { - const url = `${serverURL}${api}/${slug}` + const url = formatAdminURL({ apiRoute: api, path: `/${slug}` }) const params = new URLSearchParams() const select: SelectType = {} @@ -112,7 +111,7 @@ export const RelationshipProvider: React.FC<{ readonly children?: React.ReactNod } }) }, - [debouncedDocuments, serverURL, api, i18n, locale, collections], + [debouncedDocuments, api, i18n, locale, collections], ) useEffect(() => { diff --git a/packages/ui/src/elements/UnpublishMany/DrawerContent.tsx b/packages/ui/src/elements/UnpublishMany/DrawerContent.tsx index 1b9ab251a38..3ce7c06791f 100644 --- a/packages/ui/src/elements/UnpublishMany/DrawerContent.tsx +++ b/packages/ui/src/elements/UnpublishMany/DrawerContent.tsx @@ -2,7 +2,7 @@ import type { Where } from 'payload' import { getTranslation } from '@payloadcms/translations' import { useRouter, useSearchParams } from 'next/navigation.js' -import { combineWhereConstraints, mergeListSearchAndWhere } from 'payload/shared' +import { combineWhereConstraints, formatAdminURL, mergeListSearchAndWhere } from 'payload/shared' import * as qs from 'qs-esm' import React, { useCallback } from 'react' import { toast } from 'sonner' @@ -39,7 +39,6 @@ export function UnpublishManyDrawerContent(props: UnpublishManyDrawerContentProp const { config: { routes: { api }, - serverURL, }, } = useConfig() const { code: locale } = useLocale() @@ -93,8 +92,12 @@ export function UnpublishManyDrawerContent(props: UnpublishManyDrawerContentProp }, [collection, searchParams, selectAll, ids, locale, where]) const handleUnpublish = useCallback(async () => { + const url = formatAdminURL({ + apiRoute: api, + path: `/${slug}${queryString}`, + }) await requests - .patch(`${serverURL}${api}/${slug}${queryString}`, { + .patch(url, { body: JSON.stringify({ _status: 'draft', }), @@ -154,7 +157,6 @@ export function UnpublishManyDrawerContent(props: UnpublishManyDrawerContentProp } }) }, [ - serverURL, api, slug, queryString, diff --git a/packages/ui/src/elements/Upload/index.tsx b/packages/ui/src/elements/Upload/index.tsx index 697de03c2ff..d831f7562ed 100644 --- a/packages/ui/src/elements/Upload/index.tsx +++ b/packages/ui/src/elements/Upload/index.tsx @@ -2,7 +2,7 @@ import type { FormState, SanitizedCollectionConfig, UploadEdits } from 'payload' import { useModal } from '@faceless-ui/modal' -import { isImage } from 'payload/shared' +import { formatAdminURL, isImage } from 'payload/shared' import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react' import { toast } from 'sonner' @@ -159,7 +159,6 @@ export const Upload_v4: React.FC = (props) => { const { config: { routes: { api }, - serverURL, }, } = useConfig() @@ -290,8 +289,13 @@ export const Upload_v4: React.FC = (props) => { // Attempt server-side fetch if client-side fetch fails and useServerSideFetch is true try { - const pasteURL = `/${collectionSlug}/paste-url${id ? `/${id}?` : '?'}src=${encodeURIComponent(fileUrl)}` - const serverResponse = await fetch(`${serverURL}${api}${pasteURL}`) + const pasteURL: `/${string}` = `/${collectionSlug}/paste-url${id ? `/${id}?` : '?'}src=${encodeURIComponent(fileUrl)}` + const serverResponse = await fetch( + formatAdminURL({ + apiRoute: api, + path: pasteURL, + }), + ) if (!serverResponse.ok) { throw new Error(`Fetch failed with status: ${serverResponse.status}`) @@ -313,7 +317,6 @@ export const Upload_v4: React.FC = (props) => { fileUrl, handleFileChange, id, - serverURL, setUploadStatus, uploadConfig, uploadControlFileName, diff --git a/packages/ui/src/elements/WhereBuilder/Condition/Relationship/index.tsx b/packages/ui/src/elements/WhereBuilder/Condition/Relationship/index.tsx index 26d84101f0b..d6e2fd5c862 100644 --- a/packages/ui/src/elements/WhereBuilder/Condition/Relationship/index.tsx +++ b/packages/ui/src/elements/WhereBuilder/Condition/Relationship/index.tsx @@ -1,6 +1,7 @@ 'use client' import type { PaginatedDocs, Where } from 'payload' +import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React, { useCallback, useEffect, useReducer, useState } from 'react' @@ -13,8 +14,8 @@ import { useConfig } from '../../../../providers/Config/index.js' import { useLocale } from '../../../../providers/Locale/index.js' import { useTranslation } from '../../../../providers/Translation/index.js' import { ReactSelect } from '../../../ReactSelect/index.js' -import optionsReducer from './optionsReducer.js' import './index.scss' +import optionsReducer from './optionsReducer.js' const baseClass = 'condition-value-relationship' @@ -35,7 +36,6 @@ export const RelationshipFilter: React.FC = (props) => { const { config: { routes: { api }, - serverURL, }, getEntityConfig, } = useConfig() @@ -125,7 +125,10 @@ export const RelationshipFilter: React.FC = (props) => { try { const response = await fetch( - `${serverURL}${api}/${relationSlug}${qs.stringify(query, { addQueryPrefix: true })}`, + formatAdminURL({ + apiRoute: api, + path: `/${relationSlug}${qs.stringify(query, { addQueryPrefix: true })}`, + }), { credentials: 'include', headers: { @@ -262,12 +265,15 @@ export const RelationshipFilter: React.FC = (props) => { const addOptionByID = useCallback( async (id, relation) => { if (!errorLoading && id !== 'null' && id && relation) { - const response = await fetch(`${serverURL}${api}/${relation}/${id}?depth=0`, { - credentials: 'include', - headers: { - 'Accept-Language': i18n.language, + const response = await fetch( + formatAdminURL({ apiRoute: api, path: `/${relation}/${id}?depth=0` }), + { + credentials: 'include', + headers: { + 'Accept-Language': i18n.language, + }, }, - }) + ) if (response.ok) { const data = await response.json() @@ -278,7 +284,7 @@ export const RelationshipFilter: React.FC = (props) => { } } }, - [i18n, addOptions, api, errorLoading, serverURL, t], + [i18n, addOptions, api, errorLoading, t], ) /** diff --git a/packages/ui/src/fields/Relationship/Input.tsx b/packages/ui/src/fields/Relationship/Input.tsx index 02c49f2215a..ea3b0b5b431 100644 --- a/packages/ui/src/fields/Relationship/Input.tsx +++ b/packages/ui/src/fields/Relationship/Input.tsx @@ -284,16 +284,22 @@ export const RelationshipInput: React.FC = (props) => { sanitizeFilterOptionsQuery(query.where) - const response = await fetch(`${serverURL}${api}/${relation}`, { - body: qs.stringify(query), - credentials: 'include', - headers: { - 'Accept-Language': i18n.language, - 'Content-Type': 'application/x-www-form-urlencoded', - 'X-Payload-HTTP-Method-Override': 'GET', + const response = await fetch( + formatAdminURL({ + apiRoute: api, + path: `/${relation}`, + }), + { + body: qs.stringify(query), + credentials: 'include', + headers: { + 'Accept-Language': i18n.language, + 'Content-Type': 'application/x-www-form-urlencoded', + 'X-Payload-HTTP-Method-Override': 'GET', + }, + method: 'POST', }, - method: 'POST', - }) + ) if (response.ok) { const data: PaginatedDocs = await response.json() @@ -353,7 +359,6 @@ export const RelationshipInput: React.FC = (props) => { sortOptions, maxResultsPerRequest, locale, - serverURL, api, i18n, config, @@ -443,16 +448,22 @@ export const RelationshipInput: React.FC = (props) => { } if (!errorLoading) { - const response = await fetch(`${serverURL}${api}/${relation}`, { - body: qs.stringify(query), - credentials: 'include', - headers: { - 'Accept-Language': i18n.language, - 'Content-Type': 'application/x-www-form-urlencoded', - 'X-Payload-HTTP-Method-Override': 'GET', + const response = await fetch( + formatAdminURL({ + apiRoute: api, + path: `/${relation}`, + }), + { + body: qs.stringify(query), + credentials: 'include', + headers: { + 'Accept-Language': i18n.language, + 'Content-Type': 'application/x-www-form-urlencoded', + 'X-Payload-HTTP-Method-Override': 'GET', + }, + method: 'POST', }, - method: 'POST', - }) + ) let docs = [] if (response.ok) { diff --git a/packages/ui/src/fields/Upload/Input.tsx b/packages/ui/src/fields/Upload/Input.tsx index 9111dd316f8..3a209da20a3 100644 --- a/packages/ui/src/fields/Upload/Input.tsx +++ b/packages/ui/src/fields/Upload/Input.tsx @@ -14,6 +14,7 @@ import type { import type { MarkOptional } from 'ts-essentials' import { useModal } from '@faceless-ui/modal' +import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React, { useCallback, useEffect, useMemo } from 'react' @@ -36,8 +37,8 @@ import { useTranslation } from '../../providers/Translation/index.js' import { normalizeRelationshipValue } from '../../utilities/normalizeRelationshipValue.js' import { fieldBaseClass } from '../shared/index.js' import { UploadComponentHasMany } from './HasMany/index.js' -import { UploadComponentHasOne } from './HasOne/index.js' import './index.scss' +import { UploadComponentHasOne } from './HasOne/index.js' export const baseClass = 'upload' @@ -277,16 +278,22 @@ export function UploadInput(props: UploadInputProps) { ], }, } - const response = await fetch(`${serverURL}${api}/${collection}`, { - body: qs.stringify(query), - credentials: 'include', - headers: { - 'Accept-Language': i18n.language, - 'Content-Type': 'application/x-www-form-urlencoded', - 'X-Payload-HTTP-Method-Override': 'GET', + const response = await fetch( + formatAdminURL({ + apiRoute: api, + path: `/${collection}`, + }), + { + body: qs.stringify(query), + credentials: 'include', + headers: { + 'Accept-Language': i18n.language, + 'Content-Type': 'application/x-www-form-urlencoded', + 'X-Payload-HTTP-Method-Override': 'GET', + }, + method: 'POST', }, - method: 'POST', - }) + ) let docs: any[] = [] if (response.ok) { const data = await response.json() @@ -320,7 +327,7 @@ export function UploadInput(props: UploadInputProps) { return sortedDocs }, - [serverURL, api, code, i18n.language, t], + [api, code, i18n.language, t], ) const normalizeValue = useCallback( diff --git a/packages/ui/src/graphics/Account/index.tsx b/packages/ui/src/graphics/Account/index.tsx index 077a8744a39..e071dd79be3 100644 --- a/packages/ui/src/graphics/Account/index.tsx +++ b/packages/ui/src/graphics/Account/index.tsx @@ -16,13 +16,12 @@ export const Account = () => { routes: { account: accountRoute }, }, routes: { admin: adminRoute }, - serverURL, }, } = useConfig() const { user } = useAuth() const pathname = usePathname() - const isOnAccountPage = pathname === formatAdminURL({ adminRoute, path: accountRoute, serverURL }) + const isOnAccountPage = pathname === formatAdminURL({ adminRoute, path: accountRoute }) if (!user?.email || avatar === 'default') { return diff --git a/packages/ui/src/providers/Auth/index.tsx b/packages/ui/src/providers/Auth/index.tsx index 6375c40b258..83bee86bd9f 100644 --- a/packages/ui/src/providers/Auth/index.tsx +++ b/packages/ui/src/providers/Auth/index.tsx @@ -3,7 +3,7 @@ import type { ClientUser, SanitizedPermissions, TypedUser } from 'payload' import { useModal } from '@faceless-ui/modal' import { usePathname, useRouter } from 'next/navigation.js' -import { formatAdminURL, formatApiURL } from 'payload/shared' +import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React, { createContext, use, useCallback, useEffect, useState } from 'react' import { toast } from 'sonner' @@ -99,7 +99,6 @@ export function AuthProvider({ user: userSlug, }, routes: { admin: adminRoute, api: apiRoute }, - serverURL, } = config const { i18n } = useTranslation() @@ -120,18 +119,18 @@ export function AuthProvider({ const id = user?.id const redirectToInactivityRoute = useCallback(() => { + const baseAdminRoute = formatAdminURL({ adminRoute, path: '' }) startRouteTransition(() => router.replace( formatAdminURL({ adminRoute, - path: `${logoutInactivityRoute}${window.location.pathname.startsWith(adminRoute) ? `?redirect=${encodeURIComponent(window.location.pathname)}` : ''}`, - serverURL, + path: `${logoutInactivityRoute}${window.location.pathname.startsWith(baseAdminRoute) ? `?redirect=${encodeURIComponent(window.location.pathname)}` : ''}`, }), ), ) closeAllModals() - }, [router, adminRoute, logoutInactivityRoute, closeAllModals, startRouteTransition, serverURL]) + }, [router, adminRoute, logoutInactivityRoute, closeAllModals, startRouteTransition]) const revokeTokenAndExpire = useCallback(() => { setUserInMemory(null) @@ -198,10 +197,9 @@ export function AuthProvider({ refreshTokenTimeoutRef.current = setTimeout(async () => { try { const request = await requests.post( - formatApiURL({ + formatAdminURL({ apiRoute, path: `/${userSlug}/refresh-token?refresh`, - serverURL, }), { headers: { @@ -227,7 +225,6 @@ export function AuthProvider({ apiRoute, i18n.language, redirectToInactivityRoute, - serverURL, setNewUser, tokenExpirationMs, userSlug, @@ -240,10 +237,9 @@ export function AuthProvider({ async (skipSetUser?: boolean): Promise => { try { const request = await requests.post( - formatApiURL({ + formatAdminURL({ apiRoute, path: `/${userSlug}/refresh-token`, - serverURL, }), { headers: { @@ -269,7 +265,7 @@ export function AuthProvider({ } return null }, - [apiRoute, i18n.language, redirectToInactivityRoute, serverURL, setNewUser, userSlug, user], + [apiRoute, i18n.language, redirectToInactivityRoute, setNewUser, userSlug, user], ) const logOut = useCallback(async () => { @@ -277,10 +273,9 @@ export function AuthProvider({ if (user && user.collection) { setNewUser(null) await requests.post( - formatApiURL({ + formatAdminURL({ apiRoute, path: `/${user.collection}/logout`, - serverURL, }), ) } @@ -289,7 +284,7 @@ export function AuthProvider({ } return true - }, [apiRoute, serverURL, setNewUser, user]) + }, [apiRoute, setNewUser, user]) const refreshPermissions = useCallback( async ({ locale }: { locale?: string } = {}) => { @@ -304,10 +299,9 @@ export function AuthProvider({ try { const request = await requests.get( - formatApiURL({ + formatAdminURL({ apiRoute, path: `/access${params}`, - serverURL, }), { headers: { @@ -326,16 +320,15 @@ export function AuthProvider({ toast.error(`Refreshing permissions failed: ${e.message}`) } }, - [serverURL, apiRoute, i18n], + [apiRoute, i18n], ) const fetchFullUser = React.useCallback(async () => { try { const request = await requests.get( - formatApiURL({ + formatAdminURL({ apiRoute, path: `/${userSlug}/me`, - serverURL, }), { credentials: 'include', @@ -355,7 +348,7 @@ export function AuthProvider({ } return null - }, [serverURL, apiRoute, userSlug, i18n.language, setNewUser]) + }, [apiRoute, userSlug, i18n.language, setNewUser]) const refreshCookieEvent = useEffectEvent(refreshCookie) useEffect(() => { diff --git a/packages/ui/src/providers/DocumentInfo/index.tsx b/packages/ui/src/providers/DocumentInfo/index.tsx index 3031a199a5f..58ae098010f 100644 --- a/packages/ui/src/providers/DocumentInfo/index.tsx +++ b/packages/ui/src/providers/DocumentInfo/index.tsx @@ -1,9 +1,12 @@ 'use client' import type { ClientUser, DocumentPreferences } from 'payload' +import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React, { createContext, use, useCallback, useEffect, useMemo, useRef, useState } from 'react' +import type { DocumentInfoContext, DocumentInfoProps } from './types.js' + import { useControllableState } from '../../hooks/useControllableState.js' import { useAuth } from '../../providers/Auth/index.js' import { requests } from '../../utilities/api.js' @@ -14,7 +17,6 @@ import { useLocale, useLocaleLoading } from '../Locale/index.js' import { usePreferences } from '../Preferences/index.js' import { useTranslation } from '../Translation/index.js' import { UploadEditsProvider, useUploadEdits } from '../UploadEdits/index.js' -import { type DocumentInfoContext, type DocumentInfoProps } from './types.js' import { useGetDocPermissions } from './useGetDocPermissions.js' const Context = createContext({} as DocumentInfoContext) @@ -60,7 +62,6 @@ const DocumentInfo: React.FC< config: { admin: { dateFormat }, routes: { api }, - serverURL, }, getEntityConfig, } = useConfig() @@ -143,7 +144,11 @@ const DocumentInfo: React.FC< [initialData, initialState, localeIsLoading], ) - const baseURL = `${serverURL}${api}` + const baseAPIPath = formatAdminURL({ + apiRoute: api, + path: '', + }) + let slug: string let pluralType: 'collections' | 'globals' let preferencesKey: string @@ -168,7 +173,7 @@ const DocumentInfo: React.FC< try { const isGlobal = slug === globalSlug - const request = await requests.get(`${serverURL}${api}/payload-locked-documents`, { + const request = await requests.get(`${baseAPIPath}/payload-locked-documents`, { credentials: 'include', params: isGlobal ? { @@ -184,7 +189,7 @@ const DocumentInfo: React.FC< if (docs?.length > 0) { const lockID = docs[0].id - await requests.delete(`${serverURL}${api}/payload-locked-documents/${lockID}`, { + await requests.delete(`${baseAPIPath}/payload-locked-documents/${lockID}`, { credentials: 'include', headers: { 'Content-Type': 'application/json', @@ -197,7 +202,7 @@ const DocumentInfo: React.FC< console.error('Failed to unlock the document', error) } }, - [serverURL, api, globalSlug, setDocumentIsLocked], + [baseAPIPath, globalSlug, setDocumentIsLocked], ) const updateDocumentEditor = useCallback( @@ -206,7 +211,7 @@ const DocumentInfo: React.FC< const isGlobal = slug === globalSlug // Check if the document is already locked - const request = await requests.get(`${serverURL}${api}/payload-locked-documents`, { + const request = await requests.get(`${baseAPIPath}/payload-locked-documents`, { credentials: 'include', params: isGlobal ? { @@ -229,7 +234,7 @@ const DocumentInfo: React.FC< : { relationTo: 'users', value: user } // Send a patch request to update the _lastEdited info - await requests.patch(`${serverURL}${api}/payload-locked-documents/${lockID}`, { + await requests.patch(`${baseAPIPath}/payload-locked-documents/${lockID}`, { body: JSON.stringify({ user: userData, }), @@ -244,7 +249,7 @@ const DocumentInfo: React.FC< console.error('Failed to update the document editor', error) } }, - [serverURL, api, globalSlug], + [baseAPIPath, globalSlug], ) const getDocPermissions = useGetDocPermissions({ @@ -255,7 +260,6 @@ const DocumentInfo: React.FC< i18n, locale, permissions, - serverURL, setDocPermissions, setHasPublishPermission, setHasSavePermission, @@ -339,18 +343,20 @@ const DocumentInfo: React.FC< }, []) const action: string = React.useMemo(() => { - const docURL = `${baseURL}${pluralType === 'globals' ? `/globals` : ''}/${slug}${id ? `/${id}` : ''}` - const params = { - depth: 0, - 'fallback-locale': 'null', - locale, - uploadEdits: uploadEdits || undefined, - } - - return `${docURL}${qs.stringify(params, { - addQueryPrefix: true, - })}` - }, [baseURL, locale, pluralType, id, slug, uploadEdits]) + const docPath = `${pluralType === 'globals' ? `/globals` : ''}/${slug}${id ? `/${id}` : ''}` + + return `${baseAPIPath}${docPath}${qs.stringify( + { + depth: 0, + 'fallback-locale': 'null', + locale, + uploadEdits: uploadEdits || undefined, + }, + { + addQueryPrefix: true, + }, + )}` + }, [baseAPIPath, locale, pluralType, id, slug, uploadEdits]) const value: DocumentInfoContext = { ...props, diff --git a/packages/ui/src/providers/DocumentInfo/useGetDocPermissions.tsx b/packages/ui/src/providers/DocumentInfo/useGetDocPermissions.tsx index defcff84339..1cb2d5564a3 100644 --- a/packages/ui/src/providers/DocumentInfo/useGetDocPermissions.tsx +++ b/packages/ui/src/providers/DocumentInfo/useGetDocPermissions.tsx @@ -1,5 +1,6 @@ import type { Data, SanitizedDocumentPermissions, SanitizedPermissions } from 'payload' +import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' import React from 'react' @@ -16,7 +17,6 @@ export const useGetDocPermissions = ({ i18n, locale, permissions, - serverURL, setDocPermissions, setHasPublishPermission, setHasSavePermission, @@ -28,7 +28,6 @@ export const useGetDocPermissions = ({ id: string locale: string permissions: SanitizedPermissions - serverURL: string setDocPermissions: React.Dispatch> setHasPublishPermission: React.Dispatch> setHasSavePermission: React.Dispatch> @@ -43,30 +42,39 @@ export const useGetDocPermissions = ({ const newIsEditing = getIsEditing({ id: idToUse, collectionSlug, globalSlug }) if (newIsEditing) { - const docAccessURL = collectionSlug + const docAccessPath: `/${string}` = collectionSlug ? `/${collectionSlug}/access/${idToUse}` : globalSlug ? `/globals/${globalSlug}/access` : null - if (docAccessURL) { - const res = await fetch(`${serverURL}${api}${docAccessURL}?${qs.stringify(params)}`, { - body: JSON.stringify({ - ...(data || {}), - _status: 'draft', + if (docAccessPath) { + const res = await fetch( + formatAdminURL({ + apiRoute: api, + path: `${docAccessPath}${qs.stringify(params, { addQueryPrefix: true })}`, }), - credentials: 'include', - headers: { - 'Accept-Language': i18n.language, - 'Content-Type': 'application/json', + { + body: JSON.stringify({ + ...(data || {}), + _status: 'draft', + }), + credentials: 'include', + headers: { + 'Accept-Language': i18n.language, + 'Content-Type': 'application/json', + }, + method: 'post', }, - method: 'post', - }) + ) const json: SanitizedDocumentPermissions = await res.json() const publishedAccessJSON = await fetch( - `${serverURL}${api}${docAccessURL}?${qs.stringify(params)}`, + formatAdminURL({ + apiRoute: api, + path: `${docAccessPath}${qs.stringify(params, { addQueryPrefix: true })}`, + }), { body: JSON.stringify({ ...(data || {}), @@ -118,7 +126,6 @@ export const useGetDocPermissions = ({ id, collectionSlug, globalSlug, - serverURL, api, i18n.language, setDocPermissions, diff --git a/packages/ui/src/providers/Folders/index.tsx b/packages/ui/src/providers/Folders/index.tsx index 1ae21915af9..82ad74fe864 100644 --- a/packages/ui/src/providers/Folders/index.tsx +++ b/packages/ui/src/providers/Folders/index.tsx @@ -203,7 +203,7 @@ export function FolderProvider({ }: FolderProviderProps) { const parentFolderContext = useFolder() const { config } = useConfig() - const { routes, serverURL } = config + const { routes } = config const drawerDepth = useDrawerDepth() const { t } = useTranslation() const router = useRouter() @@ -297,10 +297,9 @@ export function FolderProvider({ return formatAdminURL({ adminRoute: config.routes.admin, path: `${baseFolderPath}${toFolderID ? `/${toFolderID}` : ''}${queryParams}`, - serverURL: config.serverURL, }) }, - [baseFolderPath, config.routes.admin, config.serverURL, mergeQuery], + [baseFolderPath, config.routes.admin, mergeQuery], ) const getItem = React.useCallback( @@ -337,7 +336,6 @@ export function FolderProvider({ formatAdminURL({ adminRoute: config.routes.admin, path: `/collections/${collectionSlug}/${docID}`, - serverURL, }), ) clearSelections() @@ -352,7 +350,6 @@ export function FolderProvider({ } }, [ - serverURL, clearSelections, config.routes.admin, drawerDepth, @@ -696,7 +693,10 @@ export function FolderProvider({ }, ) const req = await fetch( - `${serverURL}${routes.api}/${folderCollectionSlug}/${folderID}${queryParams}`, + formatAdminURL({ + apiRoute: routes.api, + path: `/${folderCollectionSlug}/${folderID}${queryParams}`, + }), { body: JSON.stringify({ [folderFieldName]: toFolderID || null }), credentials: 'include', @@ -727,14 +727,20 @@ export function FolderProvider({ }, ) try { - await fetch(`${serverURL}${routes.api}/${collectionSlug}${queryParams}`, { - body: JSON.stringify({ [folderFieldName]: toFolderID || null }), - credentials: 'include', - headers: { - 'content-type': 'application/json', + await fetch( + formatAdminURL({ + apiRoute: routes.api, + path: `/${collectionSlug}${queryParams}`, + }), + { + body: JSON.stringify({ [folderFieldName]: toFolderID || null }), + credentials: 'include', + headers: { + 'content-type': 'application/json', + }, + method: 'PATCH', }, - method: 'PATCH', - }) + ) } catch (error) { toast.error(t('general:error')) // eslint-disable-next-line no-console @@ -746,16 +752,7 @@ export function FolderProvider({ clearSelections() }, - [ - folderID, - clearSelections, - folderCollectionSlug, - folderFieldName, - routes.api, - serverURL, - t, - localeCode, - ], + [folderID, clearSelections, folderCollectionSlug, folderFieldName, routes.api, t, localeCode], ) const checkIfItemIsDisabled: FolderContextValue['checkIfItemIsDisabled'] = React.useCallback( diff --git a/packages/ui/src/providers/Locale/index.tsx b/packages/ui/src/providers/Locale/index.tsx index 3b06d052ffb..1e20b756af4 100644 --- a/packages/ui/src/providers/Locale/index.tsx +++ b/packages/ui/src/providers/Locale/index.tsx @@ -3,6 +3,7 @@ import type { Locale } from 'payload' import { useSearchParams } from 'next/navigation.js' +import { formatAdminURL } from 'payload/shared' import React, { createContext, use, useEffect, useRef, useState } from 'react' import { findLocaleFromCode } from '../../utilities/findLocaleFromCode.js' @@ -41,7 +42,6 @@ export const LocaleProvider: React.FC<{ children?: React.ReactNode; locale?: Loc config: { localization = false, routes: { api: apiRoute }, - serverURL, }, } = useConfig() @@ -83,7 +83,10 @@ export const LocaleProvider: React.FC<{ children?: React.ReactNode; locale?: Loc prevLocale.current = locale }, [locale]) - const fetchURL = `${serverURL}${apiRoute}` + const fetchURL = formatAdminURL({ + apiRoute, + path: '', + }) useEffect(() => { /** diff --git a/packages/ui/src/providers/Preferences/index.tsx b/packages/ui/src/providers/Preferences/index.tsx index 22c05c8ca14..de5c8e24a75 100644 --- a/packages/ui/src/providers/Preferences/index.tsx +++ b/packages/ui/src/providers/Preferences/index.tsx @@ -1,5 +1,6 @@ 'use client' import { dequal } from 'dequal/lite' // lite: no need for Map and Set support +import { formatAdminURL } from 'payload/shared' import React, { createContext, use, useCallback, useEffect, useRef } from 'react' import type { Preferences } from '../../forms/Form/types.js' @@ -40,7 +41,6 @@ export const PreferencesProvider: React.FC<{ children?: React.ReactNode }> = ({ const { routes: { api }, - serverURL, } = config useEffect(() => { @@ -60,12 +60,18 @@ export const PreferencesProvider: React.FC<{ children?: React.ReactNode }> = ({ const promise = new Promise((resolve: (value: T) => void) => { void (async () => { - const request = await requests.get(`${serverURL}${api}/payload-preferences/${key}`, { - credentials: 'include', - headers: { - 'Accept-Language': i18n.language, + const request = await requests.get( + formatAdminURL({ + apiRoute: api, + path: `/payload-preferences/${key}`, + }), + { + credentials: 'include', + headers: { + 'Accept-Language': i18n.language, + }, }, - }) + ) let value = null @@ -84,7 +90,7 @@ export const PreferencesProvider: React.FC<{ children?: React.ReactNode }> = ({ return promise }, - [i18n.language, api, preferencesRef, serverURL], + [i18n.language, api, preferencesRef], ) const setPreference = useCallback( @@ -93,7 +99,10 @@ export const PreferencesProvider: React.FC<{ children?: React.ReactNode }> = ({ preferencesRef.current[key] = value await requests.post( - `${serverURL}${api}/payload-preferences/${key}`, + formatAdminURL({ + apiRoute: api, + path: `/payload-preferences/${key}`, + }), requestOptions(value, i18n.language), ) @@ -141,7 +150,10 @@ export const PreferencesProvider: React.FC<{ children?: React.ReactNode }> = ({ preferencesRef.current[key] = pendingUpdate.current[key] await requests.post( - `${serverURL}${api}/payload-preferences/${key}`, + formatAdminURL({ + apiRoute: api, + path: `/payload-preferences/${key}`, + }), requestOptions(preferencesRef.current[key], i18n.language), ) @@ -154,7 +166,7 @@ export const PreferencesProvider: React.FC<{ children?: React.ReactNode }> = ({ void updatePreference() }) }, - [api, getPreference, i18n.language, pendingUpdate, serverURL], + [api, getPreference, i18n.language, pendingUpdate], ) contextRef.current.getPreference = getPreference diff --git a/packages/ui/src/providers/TableColumns/buildColumnState/renderCell.tsx b/packages/ui/src/providers/TableColumns/buildColumnState/renderCell.tsx index e747cedbacb..fa99c3e2432 100644 --- a/packages/ui/src/providers/TableColumns/buildColumnState/renderCell.tsx +++ b/packages/ui/src/providers/TableColumns/buildColumnState/renderCell.tsx @@ -80,7 +80,6 @@ export function renderCell({ const defaultURL = formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}${viewType === 'trash' ? '/trash' : ''}/${encodeURIComponent(String(doc.id))}`, - serverURL: req.payload.config.serverURL, }) const customURL = formatDocURL({ diff --git a/packages/ui/src/utilities/handleBackToDashboard.tsx b/packages/ui/src/utilities/handleBackToDashboard.tsx index 2001298c3e3..d5b25efc159 100644 --- a/packages/ui/src/utilities/handleBackToDashboard.tsx +++ b/packages/ui/src/utilities/handleBackToDashboard.tsx @@ -11,7 +11,7 @@ type BackToDashboardProps = { export const handleBackToDashboard = ({ adminRoute, router, serverURL }: BackToDashboardProps) => { const redirectRoute = formatAdminURL({ adminRoute, - path: '/', + path: '', serverURL, }) router.push(redirectRoute) diff --git a/packages/ui/src/utilities/handleGoBack.tsx b/packages/ui/src/utilities/handleGoBack.tsx index cc9023f5d54..5a4cec75055 100644 --- a/packages/ui/src/utilities/handleGoBack.tsx +++ b/packages/ui/src/utilities/handleGoBack.tsx @@ -13,7 +13,6 @@ export const handleGoBack = ({ adminRoute, collectionSlug, router, serverURL }: const redirectRoute = formatAdminURL({ adminRoute, path: collectionSlug ? `/collections/${collectionSlug}` : '/', - serverURL, }) router.push(redirectRoute) } diff --git a/packages/ui/src/views/CollectionFolder/index.tsx b/packages/ui/src/views/CollectionFolder/index.tsx index 2053026a312..445dc5b8845 100644 --- a/packages/ui/src/views/CollectionFolder/index.tsx +++ b/packages/ui/src/views/CollectionFolder/index.tsx @@ -197,7 +197,6 @@ function CollectionFolderViewInContext(props: CollectionFolderViewInContextProps formatAdminURL({ adminRoute: config.routes.admin, path: `/collections/${collectionSlug}/${config.folders.slug}`, - serverURL: config.serverURL, }), ) } @@ -226,7 +225,6 @@ function CollectionFolderViewInContext(props: CollectionFolderViewInContextProps formatAdminURL({ adminRoute: config.routes.admin, path: `/collections/${collectionSlug}/${config.folders.slug}/${crumb.id}`, - serverURL: config.serverURL, }), ) } diff --git a/packages/ui/src/views/Edit/Auth/index.tsx b/packages/ui/src/views/Edit/Auth/index.tsx index a8a97086dd4..d9a98d41b9d 100644 --- a/packages/ui/src/views/Edit/Auth/index.tsx +++ b/packages/ui/src/views/Edit/Auth/index.tsx @@ -2,7 +2,7 @@ import type { SanitizedFieldPermissions } from 'payload' -import { getFieldPermissions } from 'payload/shared' +import { formatAdminURL, getFieldPermissions } from 'payload/shared' import React, { Fragment, useCallback, useEffect, useMemo, useState } from 'react' import { toast } from 'sonner' @@ -48,7 +48,6 @@ export const Auth: React.FC = (props) => { const { config: { routes: { api }, - serverURL, }, } = useConfig() @@ -166,7 +165,10 @@ export const Auth: React.FC = (props) => { ) const unlock = useCallback(async () => { - const url = `${serverURL}${api}/${collectionSlug}/unlock` + const url = formatAdminURL({ + apiRoute: api, + path: `/${collectionSlug}/unlock`, + }) const response = await fetch(url, { body: loginWithUsername && username ? JSON.stringify({ username }) : JSON.stringify({ email }), @@ -183,7 +185,7 @@ export const Auth: React.FC = (props) => { } else { toast.error(t('authentication:failedToUnlock')) } - }, [i18n, serverURL, api, collectionSlug, email, username, t, loginWithUsername]) + }, [i18n, api, collectionSlug, email, username, t, loginWithUsername]) useEffect(() => { if (!modified) { diff --git a/packages/ui/src/views/Edit/SetDocumentStepNav/index.tsx b/packages/ui/src/views/Edit/SetDocumentStepNav/index.tsx index 5a150b2c2e4..2ed2f37fc87 100644 --- a/packages/ui/src/views/Edit/SetDocumentStepNav/index.tsx +++ b/packages/ui/src/views/Edit/SetDocumentStepNav/index.tsx @@ -57,7 +57,6 @@ export const SetDocumentStepNav: React.FC<{ ? formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}`, - serverURL, }) : undefined, }) @@ -70,7 +69,6 @@ export const SetDocumentStepNav: React.FC<{ ? formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}/trash`, - serverURL, }) : undefined, }) @@ -86,7 +84,6 @@ export const SetDocumentStepNav: React.FC<{ path: isTrashed ? `/collections/${collectionSlug}/trash/${id}` : `/collections/${collectionSlug}/${id}`, - serverURL, }) : undefined, }) @@ -102,7 +99,6 @@ export const SetDocumentStepNav: React.FC<{ ? formatAdminURL({ adminRoute, path: `/globals/${globalSlug}`, - serverURL, }) : undefined, }) diff --git a/packages/ui/src/views/Edit/index.tsx b/packages/ui/src/views/Edit/index.tsx index f18f2e7c7cd..18dbbc5bef6 100644 --- a/packages/ui/src/views/Edit/index.tsx +++ b/packages/ui/src/views/Edit/index.tsx @@ -322,7 +322,6 @@ export function DefaultEditView({ const redirectRoute = formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}/${document?.id}${locale ? `?locale=${locale}` : ''}`, - serverURL, }) startRouteTransition(() => router.push(redirectRoute)) @@ -413,7 +412,6 @@ export function DefaultEditView({ incrementVersionCount, adminRoute, locale, - serverURL, startRouteTransition, router, resetUploadEdits, diff --git a/packages/ui/src/views/List/index.tsx b/packages/ui/src/views/List/index.tsx index 1ff31aff06e..56f429c125a 100644 --- a/packages/ui/src/views/List/index.tsx +++ b/packages/ui/src/views/List/index.tsx @@ -128,7 +128,6 @@ export function DefaultListView(props: ListViewClientProps) { ? formatAdminURL({ adminRoute, path: `/collections/${collectionSlug}`, - serverURL, }) : undefined, } diff --git a/packages/ui/src/widgets/CollectionCards/index.tsx b/packages/ui/src/widgets/CollectionCards/index.tsx index 27783410e7c..518563e5c84 100644 --- a/packages/ui/src/widgets/CollectionCards/index.tsx +++ b/packages/ui/src/widgets/CollectionCards/index.tsx @@ -10,8 +10,8 @@ import { Card } from '../../elements/Card/index.js' import { Locked } from '../../elements/Locked/index.js' import { getGlobalData } from '../../utilities/getGlobalData.js' import { getNavGroups } from '../../utilities/getNavGroups.js' -import './index.scss' import { getVisibleEntities } from '../../utilities/getVisibleEntities.js' +import './index.scss' const baseClass = 'collections' @@ -22,7 +22,6 @@ export async function CollectionCards(props: WidgetServerProps) { const permissions = await getAccessResults({ req: props.req }) const visibleEntities = getVisibleEntities({ req: props.req }) const globalData = await getGlobalData(props.req) - const { serverURL } = payload.config const navGroups = getNavGroups(permissions, visibleEntities, payload.config, i18n) @@ -55,13 +54,11 @@ export async function CollectionCards(props: WidgetServerProps) { href = formatAdminURL({ adminRoute, path: `/collections/${slug}`, - serverURL, }) createHREF = formatAdminURL({ adminRoute, path: `/collections/${slug}/create`, - serverURL, }) hasCreatePermission = permissions?.collections?.[slug]?.create diff --git a/payload-types.ts b/payload-types.ts index f640cd43358..ea0cdb2f15d 100644 --- a/payload-types.ts +++ b/payload-types.ts @@ -385,6 +385,6 @@ export interface Auth { declare module 'payload' { - // @ts-ignore + // @ts-ignore export interface GeneratedTypes extends Config {} -} \ No newline at end of file +} diff --git a/templates/_template/docker-compose.yml b/templates/_template/docker-compose.yml index 4ed0d24c9ae..a93bd39918b 100644 --- a/templates/_template/docker-compose.yml +++ b/templates/_template/docker-compose.yml @@ -1,10 +1,10 @@ -version: "3" +version: '3' services: payload: image: node:18-alpine ports: - - "3000:3000" + - '3000:3000' volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -20,7 +20,7 @@ services: mongo: image: mongo:latest ports: - - "27017:27017" + - '27017:27017' command: - --storageEngine=wiredTiger volumes: diff --git a/templates/blank/docker-compose.yml b/templates/blank/docker-compose.yml index 4ed0d24c9ae..a93bd39918b 100644 --- a/templates/blank/docker-compose.yml +++ b/templates/blank/docker-compose.yml @@ -1,10 +1,10 @@ -version: "3" +version: '3' services: payload: image: node:18-alpine ports: - - "3000:3000" + - '3000:3000' volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -20,7 +20,7 @@ services: mongo: image: mongo:latest ports: - - "27017:27017" + - '27017:27017' command: - --storageEngine=wiredTiger volumes: diff --git a/templates/plugin/src/components/BeforeDashboardClient.tsx b/templates/plugin/src/components/BeforeDashboardClient.tsx index a099e3431c5..801d6d703fa 100644 --- a/templates/plugin/src/components/BeforeDashboardClient.tsx +++ b/templates/plugin/src/components/BeforeDashboardClient.tsx @@ -1,5 +1,6 @@ 'use client' import { useConfig } from '@payloadcms/ui' +import { formatAdminURL } from 'payload/shared' import { useEffect, useState } from 'react' export const BeforeDashboardClient = () => { @@ -9,7 +10,12 @@ export const BeforeDashboardClient = () => { useEffect(() => { const fetchMessage = async () => { - const response = await fetch(`${config.serverURL}${config.routes.api}/my-plugin-endpoint`) + const response = await fetch( + formatAdminURL({ + apiRoute: config.routes.api, + path: '/my-plugin-endpoint', + }), + ) const result = await response.json() setMessage(result.message) } diff --git a/templates/with-postgres/docker-compose.yml b/templates/with-postgres/docker-compose.yml index 0d684d896c7..35d00fef230 100644 --- a/templates/with-postgres/docker-compose.yml +++ b/templates/with-postgres/docker-compose.yml @@ -1,10 +1,10 @@ -version: "3" +version: '3' services: payload: image: node:20-alpine ports: - - "3000:3000" + - '3000:3000' volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -23,7 +23,7 @@ services: volumes: - pgdata:/var/lib/postgresql/data ports: - - "5432:5432" + - '5432:5432' environment: POSTGRES_USER: postgres POSTGRES_DB: your-database-name # THIS MUST MATCH YOUR DB NAME IN .env diff --git a/templates/with-vercel-mongodb/docker-compose.yml b/templates/with-vercel-mongodb/docker-compose.yml index 4ed0d24c9ae..a93bd39918b 100644 --- a/templates/with-vercel-mongodb/docker-compose.yml +++ b/templates/with-vercel-mongodb/docker-compose.yml @@ -1,10 +1,10 @@ -version: "3" +version: '3' services: payload: image: node:18-alpine ports: - - "3000:3000" + - '3000:3000' volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -20,7 +20,7 @@ services: mongo: image: mongo:latest ports: - - "27017:27017" + - '27017:27017' command: - --storageEngine=wiredTiger volumes: diff --git a/templates/with-vercel-postgres/docker-compose.yml b/templates/with-vercel-postgres/docker-compose.yml index 0d684d896c7..35d00fef230 100644 --- a/templates/with-vercel-postgres/docker-compose.yml +++ b/templates/with-vercel-postgres/docker-compose.yml @@ -1,10 +1,10 @@ -version: "3" +version: '3' services: payload: image: node:20-alpine ports: - - "3000:3000" + - '3000:3000' volumes: - .:/home/node/app - node_modules:/home/node/app/node_modules @@ -23,7 +23,7 @@ services: volumes: - pgdata:/var/lib/postgresql/data ports: - - "5432:5432" + - '5432:5432' environment: POSTGRES_USER: postgres POSTGRES_DB: your-database-name # THIS MUST MATCH YOUR DB NAME IN .env diff --git a/test/_community/payload-types.ts b/test/_community/payload-types.ts index 39b48742beb..8372cf69bbb 100644 --- a/test/_community/payload-types.ts +++ b/test/_community/payload-types.ts @@ -88,6 +88,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: { menu: Menu; }; diff --git a/test/a11y/focus-indicators.e2e.spec.ts b/test/a11y/focus-indicators.e2e.spec.ts index 7fbf2232c15..41d307c8b6d 100644 --- a/test/a11y/focus-indicators.e2e.spec.ts +++ b/test/a11y/focus-indicators.e2e.spec.ts @@ -2,9 +2,10 @@ import type { Page } from '@playwright/test' import { expect, test } from '@playwright/test' import * as path from 'path' +import { formatAdminURL } from 'payload/shared' import { fileURLToPath } from 'url' -import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { ensureCompilationIsDone, getRoutes, initPageConsoleErrorCatch } from '../helpers.js' import { checkFocusIndicators } from '../helpers/e2e/checkFocusIndicators.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' @@ -20,12 +21,18 @@ const { beforeAll, describe } = test let page: Page let serverURL: string +let adminRoute: string describe('Focus Indicators Test Page', () => { beforeAll(async ({ browser }, testInfo) => { const { serverURL: url } = await initPayloadE2ENoConfig({ dirname }) serverURL = url + const { + routes: { admin: adminRouteFromConfig }, + } = getRoutes({}) + adminRoute = adminRouteFromConfig + const context = await browser.newContext() page = await context.newPage() @@ -35,7 +42,7 @@ describe('Focus Indicators Test Page', () => { describe('Full Page Scan', () => { test('should detect all focusable elements on the page', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) await page.locator('.focus-indicators-test-page').waitFor() const result = await checkFocusIndicators({ @@ -57,7 +64,7 @@ describe('Focus Indicators Test Page', () => { describe('Section 1: Good Payload Components', () => { test('should pass for all Payload buttons', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) await page.locator('[data-testid="section-good-payload"]').waitFor() const result = await checkFocusIndicators({ @@ -76,7 +83,7 @@ describe('Focus Indicators Test Page', () => { describe('Section 2: Good HTML Elements', () => { test('should pass for standard HTML with good focus styles', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) await page.locator('[data-testid="section-good-html"]').waitFor() const result = await checkFocusIndicators({ @@ -95,7 +102,7 @@ describe('Focus Indicators Test Page', () => { }) test('should detect specific good buttons by ID', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -117,7 +124,7 @@ describe('Focus Indicators Test Page', () => { describe('Section 3: Pseudo-element Focus Indicators', () => { test('should detect focus indicators on ::after and ::before pseudo-elements', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) await page.locator('[data-testid="section-pseudo"]').waitFor() const result = await checkFocusIndicators({ @@ -144,7 +151,7 @@ describe('Focus Indicators Test Page', () => { describe('Section 4: Bad Focus Indicators (Expected Failures)', () => { test('should fail for elements without focus indicators', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) await page.locator('[data-testid="section-bad"]').waitFor() const result = await checkFocusIndicators({ @@ -163,7 +170,7 @@ describe('Focus Indicators Test Page', () => { }) test('should identify specific bad elements by ID', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -184,7 +191,7 @@ describe('Focus Indicators Test Page', () => { }) test('should provide useful selectors for violations', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -208,7 +215,7 @@ describe('Focus Indicators Test Page', () => { describe('Section 5: Mixed Focus Indicators', () => { test('should correctly identify mix of good and bad elements', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) await page.locator('[data-testid="section-mixed"]').waitFor() const result = await checkFocusIndicators({ @@ -227,7 +234,7 @@ describe('Focus Indicators Test Page', () => { }) test('should correctly categorize good vs bad in mixed section', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -250,7 +257,7 @@ describe('Focus Indicators Test Page', () => { describe('Section 6: Edge Cases', () => { test('should fail for edge cases with non-visible focus indicators', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) await page.locator('[data-testid="section-edge-cases"]').waitFor() const result = await checkFocusIndicators({ @@ -269,7 +276,7 @@ describe('Focus Indicators Test Page', () => { }) test('should detect zero-width borders as invalid', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -283,7 +290,7 @@ describe('Focus Indicators Test Page', () => { }) test('should detect zero-opacity shadows as invalid', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -297,7 +304,7 @@ describe('Focus Indicators Test Page', () => { }) test('should detect transparent outlines as invalid', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -311,7 +318,7 @@ describe('Focus Indicators Test Page', () => { }) test('should pass for focusable div with good focus indicator', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -327,7 +334,7 @@ describe('Focus Indicators Test Page', () => { describe('Section 7: Disabled Elements', () => { test('should not include disabled elements in tab order', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) await page.locator('[data-testid="section-disabled"]').waitFor() const result = await checkFocusIndicators({ @@ -348,7 +355,7 @@ describe('Focus Indicators Test Page', () => { describe('Utility Validation', () => { test('should limit focusable elements count with maxFocusableElements', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -363,7 +370,7 @@ describe('Focus Indicators Test Page', () => { }) test('should run axe scans on each focused element when runAxeOnElements is true', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -393,7 +400,7 @@ describe('Focus Indicators Test Page', () => { }) test('should detect axe violations on specific elements', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -417,7 +424,7 @@ describe('Focus Indicators Test Page', () => { }) test('should provide detailed violation information', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const result = await checkFocusIndicators({ page, @@ -444,7 +451,7 @@ describe('Focus Indicators Test Page', () => { }) test('should attach results to test info', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) await checkFocusIndicators({ page, @@ -467,7 +474,7 @@ describe('Focus Indicators Test Page', () => { describe('Performance & Limits', () => { test('should handle scanning large sections efficiently', async ({}, testInfo) => { - await page.goto(`${serverURL}/admin/focus-indicators`) + await page.goto(formatAdminURL({ adminRoute, path: '/focus-indicators', serverURL })) const startTime = Date.now() diff --git a/test/access-control/e2e.spec.ts b/test/access-control/e2e.spec.ts index cbe9f3e3860..63c7cdb7ebb 100644 --- a/test/access-control/e2e.spec.ts +++ b/test/access-control/e2e.spec.ts @@ -3,7 +3,7 @@ import type { TypeWithID } from 'payload' import { expect, test } from '@playwright/test' import path from 'path' -import { wait } from 'payload/shared' +import { formatAdminURL, wait } from 'payload/shared' import { fileURLToPath } from 'url' import type { PayloadTestSDK } from '../helpers/sdk/index.js' @@ -621,7 +621,7 @@ describe('Access Control', () => { }) test('should restrict access based on user settings', async () => { - const url = `${serverURL}/admin/globals/settings` + const url = formatAdminURL({ adminRoute: '/admin', path: '/globals/settings', serverURL }) await page.goto(url) await openNav(page) await expect(page.locator('#nav-global-settings')).toBeVisible() diff --git a/test/admin-bar/e2e.spec.ts b/test/admin-bar/e2e.spec.ts index b9c2f9026d9..8bd2f89db0e 100644 --- a/test/admin-bar/e2e.spec.ts +++ b/test/admin-bar/e2e.spec.ts @@ -2,6 +2,7 @@ import type { Page } from '@playwright/test' import { expect, test } from '@playwright/test' import * as path from 'path' +import { formatAdminURL } from 'payload/shared' import { fileURLToPath } from 'url' import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' @@ -31,7 +32,7 @@ test.describe('Admin Bar', () => { }) test('should render admin bar', async () => { - await page.goto(`${serverURL}/admin-bar`) + await page.goto(formatAdminURL({ adminRoute: '/admin-bar', path: '', serverURL })) await expect(page.locator('#payload-admin-bar')).toBeVisible() }) }) diff --git a/test/admin-bar/payload-types.ts b/test/admin-bar/payload-types.ts index dabf1feec44..2cbdee44b74 100644 --- a/test/admin-bar/payload-types.ts +++ b/test/admin-bar/payload-types.ts @@ -69,6 +69,7 @@ export interface Config { collections: { posts: Post; media: Media; + 'payload-kv': PayloadKv; users: User; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -78,6 +79,7 @@ export interface Config { collectionsSelect: { posts: PostsSelect | PostsSelect; media: MediaSelect | MediaSelect; + 'payload-kv': PayloadKvSelect | PayloadKvSelect; users: UsersSelect | UsersSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -86,6 +88,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: {}; globalsSelect: {}; locale: null; @@ -170,6 +173,23 @@ export interface Media { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv". + */ +export interface PayloadKv { + id: string; + key: string; + data: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -185,6 +205,13 @@ export interface User { hash?: string | null; loginAttempts?: number | null; lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; password?: string | null; } /** @@ -309,6 +336,14 @@ export interface MediaSelect { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv_select". + */ +export interface PayloadKvSelect { + key?: T; + data?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". @@ -323,6 +358,13 @@ export interface UsersSelect { hash?: T; loginAttempts?: T; lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; } /** * This interface was referenced by `Config`'s JSON-Schema diff --git a/test/admin-root/payload-types.ts b/test/admin-root/payload-types.ts index 4ca79e12daf..6c11b216f73 100644 --- a/test/admin-root/payload-types.ts +++ b/test/admin-root/payload-types.ts @@ -68,6 +68,7 @@ export interface Config { blocks: {}; collections: { posts: Post; + 'payload-kv': PayloadKv; users: User; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -76,6 +77,7 @@ export interface Config { collectionsJoins: {}; collectionsSelect: { posts: PostsSelect | PostsSelect; + 'payload-kv': PayloadKvSelect | PayloadKvSelect; users: UsersSelect | UsersSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -84,6 +86,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: { menu: Menu; }; @@ -128,6 +131,23 @@ export interface Post { createdAt: string; _status?: ('draft' | 'published') | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv". + */ +export interface PayloadKv { + id: string; + key: string; + data: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -143,6 +163,13 @@ export interface User { hash?: string | null; loginAttempts?: number | null; lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; password?: string | null; } /** @@ -212,6 +239,14 @@ export interface PostsSelect { createdAt?: T; _status?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv_select". + */ +export interface PayloadKvSelect { + key?: T; + data?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". @@ -226,6 +261,13 @@ export interface UsersSelect { hash?: T; loginAttempts?: T; lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; } /** * This interface was referenced by `Config`'s JSON-Schema diff --git a/test/admin/config.ts b/test/admin/config.ts index 9d93331876c..3bfd6fe58fc 100644 --- a/test/admin/config.ts +++ b/test/admin/config.ts @@ -45,6 +45,7 @@ import { GlobalNotInView } from './globals/NotInView.js' import { Settings } from './globals/Settings.js' import { seed } from './seed.js' import { + BASE_PATH, customAdminRoutes, customNestedViewPath, customParamViewPath, @@ -54,6 +55,7 @@ import { publicCustomViewPath, } from './shared.js' import { editMenuItemsSlug, reorderTabsSlug } from './slugs.js' +process.env.NEXT_BASE_PATH = BASE_PATH const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) diff --git a/test/admin/e2e/document-view/e2e.spec.ts b/test/admin/e2e/document-view/e2e.spec.ts index 52d1e072d7b..82c7e853b97 100644 --- a/test/admin/e2e/document-view/e2e.spec.ts +++ b/test/admin/e2e/document-view/e2e.spec.ts @@ -16,6 +16,7 @@ import { import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js' import { + BASE_PATH, customAdminRoutes, customEditLabel, customNestedTabViewPath, @@ -42,6 +43,7 @@ import { postsCollectionSlug, reorderTabsSlug, } from '../../slugs.js' +process.env.NEXT_BASE_PATH = BASE_PATH const { beforeAll, beforeEach, describe } = test diff --git a/test/admin/e2e/general/e2e.spec.ts b/test/admin/e2e/general/e2e.spec.ts index 1fe2b800dd7..41c36b3b02a 100644 --- a/test/admin/e2e/general/e2e.spec.ts +++ b/test/admin/e2e/general/e2e.spec.ts @@ -1,6 +1,7 @@ import type { BrowserContext, Page } from '@playwright/test' import { expect, test } from '@playwright/test' +import { formatAdminURL, wait } from 'payload/shared' import type { Config, Geo, Post } from '../../payload-types.js' @@ -15,6 +16,7 @@ import { import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js' import { + BASE_PATH, customAdminRoutes, customCollectionMetaTitle, customDefaultTabMetaTitle, @@ -41,6 +43,7 @@ import { settingsGlobalSlug, uploadTwoCollectionSlug, } from '../../slugs.js' +process.env.NEXT_BASE_PATH = BASE_PATH const { beforeAll, beforeEach, describe } = test @@ -49,15 +52,14 @@ const description = 'Description' let payload: PayloadTestSDK -import { navigateToDoc } from 'helpers/e2e/navigateToDoc.js' -import { openDocControls } from 'helpers/e2e/openDocControls.js' -import { openNav } from 'helpers/e2e/toggleNav.js' import path from 'path' -import { wait } from 'payload/shared' import { fileURLToPath } from 'url' import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' +import { navigateToDoc } from '../../../helpers/e2e/navigateToDoc.js' +import { openDocControls } from '../../../helpers/e2e/openDocControls.js' +import { openNav } from '../../../helpers/e2e/toggleNav.js' import { reInitializeDB } from '../../../helpers/reInitializeDB.js' import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../../../playwright.config.js' const filename = fileURLToPath(import.meta.url) @@ -76,6 +78,7 @@ describe('General', () => { let disableDuplicateURL: AdminUrlUtil let serverURL: string let adminRoutes: ReturnType + let adminRoute: string let uploadsTwo: AdminUrlUtil beforeAll(async ({ browser }, testInfo) => { @@ -104,6 +107,7 @@ describe('General', () => { await ensureCompilationIsDone({ customAdminRoutes, page, serverURL }) adminRoutes = getRoutes({ customAdminRoutes }) + adminRoute = adminRoutes.routes.admin }) beforeEach(async () => { @@ -124,12 +128,12 @@ describe('General', () => { describe('metadata', () => { describe('root title and description', () => { test('should render custom page title suffix', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ path: '', serverURL, adminRoute })) await expect(page.title()).resolves.toMatch(/- Custom Title Suffix$/) }) test('should render custom meta description from root config', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ path: '', serverURL, adminRoute })) await expect(page.locator('meta[name="description"]')).toHaveAttribute( 'content', /This is a custom meta description/, @@ -147,12 +151,24 @@ describe('General', () => { }) test('should fallback to root meta for custom root views', async () => { - await page.goto(`${serverURL}/admin/custom-default-view`) + await page.goto( + formatAdminURL({ + path: '/custom-default-view', + serverURL, + adminRoute, + }), + ) await expect(page.title()).resolves.toMatch(/- Custom Title Suffix$/) }) test('should render custom meta title from custom root views', async () => { - await page.goto(`${serverURL}/admin/custom-minimal-view`) + await page.goto( + formatAdminURL({ + path: '/custom-minimal-view', + serverURL, + adminRoute, + }), + ) const pattern = new RegExp(`^${customRootViewMetaTitle}`) await expect(page.title()).resolves.toMatch(pattern) }) @@ -160,7 +176,7 @@ describe('General', () => { describe('robots', () => { test('should apply default robots meta tag', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ path: '', serverURL, adminRoute })) await expect(page.locator('meta[name="robots"]')).toHaveAttribute( 'content', /noindex, nofollow/, @@ -188,7 +204,7 @@ describe('General', () => { describe('og meta', () => { test('should render custom og:title from root config', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ path: '', serverURL, adminRoute })) await expect(page.locator('meta[property="og:title"]')).toHaveAttribute( 'content', /This is a custom OG title/, @@ -196,7 +212,7 @@ describe('General', () => { }) test('should render custom og:description from root config', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ path: '', serverURL, adminRoute })) await expect(page.locator('meta[property="og:description"]')).toHaveAttribute( 'content', /This is a custom OG description/, @@ -341,25 +357,43 @@ describe('General', () => { describe('routing', () => { test('should 404 not found root pages', async () => { - const unknownPageURL = `${serverURL}/admin/1234` + const unknownPageURL = formatAdminURL({ + path: '/1234', + serverURL, + adminRoute, + }) const response = await page.goto(unknownPageURL) expect(response.status() === 404).toBeTruthy() await expect(page.locator('.not-found')).toContainText('Nothing found') }) test('should use custom logout route', async () => { - const customLogoutRouteURL = `${serverURL}${adminRoutes.routes.admin}${adminRoutes.admin.routes.logout}` + const customLogoutRouteURL = formatAdminURL({ + adminRoute, + path: adminRoutes.admin.routes.logout, + serverURL, + }) const response = await page.goto(customLogoutRouteURL) expect(response.status() !== 404).toBeTruthy() }) test('should redirect from non-existent document ID to collection list', async () => { - const nonExistentDocURL = `${serverURL}/admin/collections/${postsCollectionSlug}/999999` + const nonExistentDocURL = formatAdminURL({ + path: `/collections/${postsCollectionSlug}/999999`, + serverURL, + adminRoute, + }) await page.goto(nonExistentDocURL) // Should redirect to collection list with notFound query parameter await expect .poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }) - .toMatch(`${serverURL}/admin/collections/${postsCollectionSlug}?notFound=999999`) + .toMatch( + formatAdminURL({ + path: `/collections/${postsCollectionSlug}?notFound=999999`, + serverURL, + adminRoute, + }), + ) // Should show warning banner about document not found await expect(page.locator('.banner--type-error')).toBeVisible() @@ -367,16 +401,24 @@ describe('General', () => { }) test('should not redirect `${adminRoute}/collections` to `${adminRoute} if there is a custom view', async () => { - const collectionsURL = `${serverURL}/admin/collections` + const collectionsURL = formatAdminURL({ + path: '/collections', + serverURL, + adminRoute, + }) await page.goto(collectionsURL) await expect(page.getByText('Custom View').first()).toBeVisible() }) test('should redirect `${adminRoute}/globals` to `${adminRoute}', async () => { - const globalsURL = `${serverURL}/admin/globals` + const globalsURL = formatAdminURL({ + path: '/globals', + serverURL, + adminRoute, + }) await page.goto(globalsURL) // Should redirect to dashboard - await expect.poll(() => page.url()).toBe(`${serverURL}/admin`) + await expect.poll(() => page.url()).toBe(formatAdminURL({ path: '', serverURL, adminRoute })) }) /** @@ -553,7 +595,11 @@ describe('General', () => { test('breadcrumbs — should navigate from list to dashboard', async () => { await page.goto(postsUrl.list) - await page.locator(`.step-nav a[href="${adminRoutes.routes.admin}"]`).click() + await page + .locator( + `.step-nav a[href="${formatAdminURL({ path: '', includeBasePath: true, adminRoute })}"]`, + ) + .click() expect(page.url()).toContain(postsUrl.admin) }) @@ -561,7 +607,7 @@ describe('General', () => { const { id } = await createPost() await page.goto(postsUrl.edit(id)) const collectionBreadcrumb = page.locator( - `.step-nav a[href="${adminRoutes.routes.admin}/collections/${postsCollectionSlug}"]`, + `.step-nav a[href="${formatAdminURL({ path: `/collections/${postsCollectionSlug}`, includeBasePath: true, adminRoute })}"]`, ) await expect(collectionBreadcrumb).toBeVisible() await expect(collectionBreadcrumb).toHaveText(slugPluralLabel) @@ -642,13 +688,13 @@ describe('General', () => { describe('custom providers', () => { test('should render custom providers', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ path: '', serverURL, adminRoute })) await expect(page.locator('.custom-provider')).toHaveCount(1) await expect(page.locator('.custom-provider')).toContainText('This is a custom provider.') }) test('should render custom provider server components with props', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ path: '', serverURL, adminRoute })) await expect(page.locator('.custom-provider-server')).toHaveCount(1) await expect(page.locator('.custom-provider-server')).toContainText( 'This is a custom provider with payload: true', @@ -658,12 +704,18 @@ describe('General', () => { describe('custom root views', () => { test('should render custom view', async () => { - await page.goto(`${serverURL}${adminRoutes.routes.admin}${customViewPath}`) + await page.goto(formatAdminURL({ adminRoute, path: customViewPath, serverURL })) await expect(page.locator('h1#custom-view-title')).toContainText(customViewTitle) }) test('should render custom nested view', async () => { - await page.goto(`${serverURL}${adminRoutes.routes.admin}${customNestedViewPath}`) + await page.goto( + formatAdminURL({ + adminRoute, + path: customNestedViewPath, + serverURL, + }), + ) const pageURL = page.url() const pathname = new URL(pageURL).pathname expect(pathname).toEqual(`${adminRoutes.routes.admin}${customNestedViewPath}`) @@ -671,12 +723,24 @@ describe('General', () => { }) test('should render public custom view', async () => { - await page.goto(`${serverURL}${adminRoutes.routes.admin}${publicCustomViewPath}`) + await page.goto( + formatAdminURL({ + adminRoute, + path: publicCustomViewPath, + serverURL, + }), + ) await expect(page.locator('h1#custom-view-title')).toContainText(customViewTitle) }) test('should render protected nested custom view', async () => { - await page.goto(`${serverURL}${adminRoutes.routes.admin}${protectedCustomNestedViewPath}`) + await page.goto( + formatAdminURL({ + adminRoute, + path: protectedCustomNestedViewPath, + serverURL, + }), + ) // wait for redirect to unauthorized page await page.waitForURL(`**${adminRoutes.routes.admin}/unauthorized`) @@ -690,7 +754,13 @@ describe('General', () => { await saveDocAndAssert(page) - await page.goto(`${serverURL}${adminRoutes.routes.admin}${protectedCustomNestedViewPath}`) + await page.goto( + formatAdminURL({ + adminRoute, + path: protectedCustomNestedViewPath, + serverURL, + }), + ) await expect(page.locator('h1#custom-view-title')).toContainText(customNestedViewTitle) }) }) @@ -703,7 +773,7 @@ describe('General', () => { }) test('should show admin level action in collection list view', async () => { - await page.goto(`${new AdminUrlUtil(serverURL, 'geo').list}`) + await page.goto(new AdminUrlUtil(serverURL, 'geo').list) await expect(page.locator('.app-header .admin-button')).toHaveCount(1) }) @@ -714,7 +784,7 @@ describe('General', () => { }) test('should show collection list view level action in collection list view', async () => { - await page.goto(`${new AdminUrlUtil(serverURL, 'geo').list}`) + await page.goto(new AdminUrlUtil(serverURL, 'geo').list) await expect(page.locator('.app-header .collection-list-button')).toHaveCount(1) }) @@ -753,7 +823,7 @@ describe('General', () => { describe('custom components', () => { test('should render custom header', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ path: '', serverURL, adminRoute })) const header = page.locator('.custom-header') await expect(header).toContainText('Here is a custom header') }) @@ -949,7 +1019,7 @@ describe('General', () => { describe('preferences', () => { test('should successfully reset prefs after clicking reset button', async () => { - await page.goto(`${serverURL}/admin/account`) + await page.goto(formatAdminURL({ path: '/account', serverURL, adminRoute })) const resetPrefsButton = page.locator('.payload-settings > div > button.btn') await expect(resetPrefsButton).toBeVisible() await resetPrefsButton.click() diff --git a/test/admin/e2e/list-view/e2e.spec.ts b/test/admin/e2e/list-view/e2e.spec.ts index ecb1e21cb84..25eb4705863 100644 --- a/test/admin/e2e/list-view/e2e.spec.ts +++ b/test/admin/e2e/list-view/e2e.spec.ts @@ -15,7 +15,7 @@ import { } from '../../../helpers.js' import { AdminUrlUtil } from '../../../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../../../helpers/initPayloadE2ENoConfig.js' -import { customAdminRoutes } from '../../shared.js' +import { BASE_PATH, customAdminRoutes } from '../../shared.js' import { arrayCollectionSlug, customViews1CollectionSlug, @@ -27,6 +27,7 @@ import { virtualsSlug, with300DocumentsSlug, } from '../../slugs.js' +process.env.NEXT_BASE_PATH = BASE_PATH const { beforeAll, beforeEach, describe } = test diff --git a/test/admin/shared.ts b/test/admin/shared.ts index 107f4734efe..5a9d146f737 100644 --- a/test/admin/shared.ts +++ b/test/admin/shared.ts @@ -62,3 +62,5 @@ export const customAdminRoutes: Config['admin']['routes'] = { inactivity: '/custom-inactivity', logout: '/custom-logout', } + +export const BASE_PATH: '' | `/${string}` = '' diff --git a/test/auth-basic/e2e.spec.ts b/test/auth-basic/e2e.spec.ts index db9783130f2..0b2e69033c2 100644 --- a/test/auth-basic/e2e.spec.ts +++ b/test/auth-basic/e2e.spec.ts @@ -4,6 +4,7 @@ import type { SanitizedConfig } from 'payload' import { expect, test } from '@playwright/test' import { devUser } from 'credentials.js' import path from 'path' +import { formatAdminURL } from 'payload/shared' import { fileURLToPath } from 'url' import type { PayloadTestSDK } from '../helpers/sdk/index.js' @@ -72,6 +73,7 @@ describe('Auth (Basic)', () => { let page: Page let url: AdminUrlUtil let serverURL: string + let adminRoute: string beforeAll(async ({ browser }, testInfo) => { testInfo.setTimeout(TEST_TIMEOUT_LONG) @@ -81,11 +83,15 @@ describe('Auth (Basic)', () => { const context = await browser.newContext() page = await context.newPage() initPageConsoleErrorCatch(page) + const { + routes: { admin }, + } = getRoutes({}) + adminRoute = admin await ensureCompilationIsDone({ page, serverURL, - readyURL: `${serverURL}/admin/**`, + readyURL: formatAdminURL({ path: '/**', serverURL, adminRoute }), noAutoLogin: true, }) @@ -108,7 +114,7 @@ describe('Auth (Basic)', () => { await ensureCompilationIsDone({ page, serverURL, - readyURL: `${serverURL}/admin/create-first-user`, + readyURL: formatAdminURL({ path: '/create-first-user', serverURL, adminRoute }), }) }) diff --git a/test/auth/AuthDebug.tsx b/test/auth/AuthDebug.tsx index 785adcf0710..9ca7bf12e7f 100644 --- a/test/auth/AuthDebug.tsx +++ b/test/auth/AuthDebug.tsx @@ -3,15 +3,21 @@ import type { UIField, User } from 'payload' import { useAuth } from '@payloadcms/ui' +import { formatAdminURL } from 'payload/shared' import React, { useEffect, useState } from 'react' export const AuthDebug: React.FC = () => { - const [state, setState] = useState() + const [state, setState] = useState() const { user } = useAuth() useEffect(() => { const fetchUser = async () => { - const userRes = await fetch(`/api/users/${user?.id}`)?.then((res) => res.json()) + const userRes = await fetch( + formatAdminURL({ + apiRoute: '/api', + path: `/users/${user?.id}`, + }), + )?.then((res) => res.json()) setState(userRes) } diff --git a/test/auth/config.ts b/test/auth/config.ts index b7fb9581000..4e5451c075c 100644 --- a/test/auth/config.ts +++ b/test/auth/config.ts @@ -7,6 +7,7 @@ import { devUser } from '../credentials.js' import { seed } from './seed.js' import { apiKeysSlug, + BASE_PATH, namedSaveToJWTValue, partialDisableLocalStrategiesSlug, publicUsersSlug, @@ -14,6 +15,8 @@ import { slug, } from './shared.js' +process.env.NEXT_BASE_PATH = BASE_PATH + export default buildConfigWithDefaults({ admin: { autoLogin: { diff --git a/test/auth/e2e.spec.ts b/test/auth/e2e.spec.ts index 62cfed96f64..d01c36632be 100644 --- a/test/auth/e2e.spec.ts +++ b/test/auth/e2e.spec.ts @@ -6,6 +6,7 @@ import { login } from 'helpers/e2e/auth/login.js' import { logout } from 'helpers/e2e/auth/logout.js' import { openNav } from 'helpers/e2e/toggleNav.js' import path from 'path' +import { formatAdminURL } from 'payload/shared' import { fileURLToPath } from 'url' import { v4 as uuid } from 'uuid' @@ -23,10 +24,11 @@ import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { reInitializeDB } from '../helpers/reInitializeDB.js' import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js' -import { apiKeysSlug, slug } from './shared.js' +import { apiKeysSlug, BASE_PATH, slug } from './shared.js' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) +process.env.NEXT_BASE_PATH = BASE_PATH let payload: PayloadTestSDK @@ -42,13 +44,19 @@ describe('Auth', () => { let url: AdminUrlUtil let serverURL: string let apiURL: string + let adminRoute: string beforeAll(async ({ browser }, testInfo) => { testInfo.setTimeout(TEST_TIMEOUT_LONG) ;({ payload, serverURL } = await initPayloadE2ENoConfig({ dirname })) - apiURL = `${serverURL}/api` + apiURL = formatAdminURL({ apiRoute: '/api', path: '', serverURL }) url = new AdminUrlUtil(serverURL, slug) + const { + routes: { admin: adminRouteFromConfig }, + } = getRoutes({}) + adminRoute = adminRouteFromConfig + context = await browser.newContext() page = await context.newPage() initPageConsoleErrorCatch(page) @@ -89,7 +97,7 @@ describe('Auth', () => { } = getRoutes({}) // wait for create first user route - await page.goto(serverURL + `${adminRoute}${createFirstUserRoute}`) + await page.goto(formatAdminURL({ adminRoute, path: createFirstUserRoute, serverURL })) await expect(page.locator('.create-first-user')).toBeVisible() @@ -141,7 +149,7 @@ describe('Auth', () => { } = getRoutes({}) // wait for create first user route - await page.goto(serverURL + `${adminRoute}${createFirstUserRoute}`) + await page.goto(formatAdminURL({ adminRoute, path: createFirstUserRoute, serverURL })) await expect(page.locator('.create-first-user')).toBeVisible() @@ -196,7 +204,9 @@ describe('Auth', () => { await logout(page, serverURL) // Inspect the page source (before authentication) - const loginPageRes = await page.goto(`${serverURL}/admin/login`) + const loginPageRes = await page.goto( + formatAdminURL({ adminRoute, path: '/login', serverURL }), + ) const loginPageSource = await loginPageRes?.text() expect(loginPageSource).not.toContain('shouldNotShowInClientConfigUnlessAuthenticated') @@ -211,7 +221,7 @@ describe('Auth', () => { await login({ page, serverURL }) - await page.goto(serverURL + '/admin') + await page.goto(formatAdminURL({ adminRoute, path: '', serverURL })) // Inspect the client config (after authentication) await expect(page.locator('#authenticated-client-config')).toBeAttached() @@ -223,7 +233,9 @@ describe('Auth', () => { ).toHaveCount(1) // Inspect the page source (after authentication) - const dashboardPageRes = await page.goto(`${serverURL}/admin`) + const dashboardPageRes = await page.goto( + formatAdminURL({ adminRoute, path: '', serverURL }), + ) const dashboardPageSource = await dashboardPageRes?.text() expect(dashboardPageSource).toContain('shouldNotShowInClientConfigUnlessAuthenticated') }) @@ -265,11 +277,12 @@ describe('Auth', () => { }) test('should prevent new user creation without confirm password', async () => { + await page.goto(url.list) await page.goto(url.create) await page.locator('#field-email').fill('dev2@payloadcms.com') await page.locator('#field-password').fill('password') // should fail to save without confirm password - await page.locator('#action-save').click() + await page.locator('#action-save').click({ delay: 100 }) await expect( page.locator('.field-type.confirm-password .tooltip--show', { hasText: exactText('This field is required.'), @@ -324,8 +337,11 @@ describe('Auth', () => { await expect.poll(() => lockedDocs.docs.length).toBe(1) await openNav(page) - - await page.locator('.nav .nav__controls a[href="/admin/logout"]').click() + await page + .locator( + `.nav .nav__controls a[href="${formatAdminURL({ includeBasePath: true, path: '/logout', adminRoute: '/admin' })}"]`, + ) + .click() // Locate the modal container const modalContainer = page.locator('.payload__modal-container') @@ -447,7 +463,11 @@ describe('Auth', () => { limit: 1, }) - const userDocumentRoute = `${serverURL}/admin/collections/users/${users?.docs?.[0]?.id}` + const userDocumentRoute = formatAdminURL({ + adminRoute, + path: `/collections/users/${users?.docs?.[0]?.id}`, + serverURL, + }) await logout(page, serverURL) @@ -480,9 +500,12 @@ describe('Auth', () => { await logout(page, serverURL) - await page.goto( - `${serverURL}/admin/collections/relationsCollection/${notInUserCollection.id}`, - ) + const notInUserCollectionURL = formatAdminURL({ + adminRoute, + path: `/collections/relationsCollection/${notInUserCollection.id}`, + serverURL, + }) + await page.goto(notInUserCollectionURL) await expect .poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }) @@ -497,7 +520,7 @@ describe('Auth', () => { // Expect to be redirected to the correct page await expect .poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }) - .toBe(`${serverURL}/admin/collections/relationsCollection/${notInUserCollection.id}`) + .toBe(notInUserCollectionURL) // Previously, this would crash the page with a "Cannot read properties of null (reading 'fields')" error await expect(page.locator('#field-rel')).toBeVisible() diff --git a/test/auth/shared.ts b/test/auth/shared.ts index 570ed4c905b..9cdf94af1b9 100644 --- a/test/auth/shared.ts +++ b/test/auth/shared.ts @@ -9,3 +9,5 @@ export const partialDisableLocalStrategiesSlug = 'partial-disable-local-strategi export const namedSaveToJWTValue = 'namedSaveToJWT value' export const saveToJWTKey = 'x-custom-jwt-property-name' + +export const BASE_PATH: '' | `/${string}` = '' diff --git a/test/base-path/.gitignore b/test/base-path/.gitignore new file mode 100644 index 00000000000..a9a101f8cff --- /dev/null +++ b/test/base-path/.gitignore @@ -0,0 +1,4 @@ +.next +node_modules +payload-types.ts +schema.graphql diff --git a/test/base-path/collections/Posts.ts b/test/base-path/collections/Posts.ts new file mode 100644 index 00000000000..e3ff13f4572 --- /dev/null +++ b/test/base-path/collections/Posts.ts @@ -0,0 +1,19 @@ +import type { CollectionConfig } from 'payload' + +export const Posts: CollectionConfig = { + slug: 'posts', + admin: { + useAsTitle: 'title', + }, + fields: [ + { + name: 'title', + type: 'text', + required: true, + }, + { + name: 'content', + type: 'textarea', + }, + ], +} diff --git a/test/base-path/config.ts b/test/base-path/config.ts new file mode 100644 index 00000000000..5c478714304 --- /dev/null +++ b/test/base-path/config.ts @@ -0,0 +1,28 @@ +import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' +import { Posts } from './collections/Posts.js' +import { seed } from './seed/index.js' +import { BASE_PATH } from './shared.js' + +process.env.NEXT_BASE_PATH = BASE_PATH + +export default buildConfigWithDefaults({ + collections: [ + Posts, + { + slug: 'media', + upload: true, + fields: [], + }, + ], + onInit: seed, + serverURL: 'http://localhost:3000', + endpoints: [ + { + handler: () => { + return new Response('Custom Endpoint Response') + }, + path: '/custom-endpoint', + method: 'get', + }, + ], +}) diff --git a/test/base-path/e2e.spec.ts b/test/base-path/e2e.spec.ts new file mode 100644 index 00000000000..cb43c19a2c7 --- /dev/null +++ b/test/base-path/e2e.spec.ts @@ -0,0 +1,83 @@ +import type { Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import path from 'path' +import { fileURLToPath } from 'url' + +import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js' +import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' +import { goToListDoc } from '../helpers/e2e/goToListDoc.js' +import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' +import { TEST_TIMEOUT_LONG } from '../playwright.config.js' +import { BASE_PATH } from './shared.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +process.env.NEXT_BASE_PATH = BASE_PATH + +test.describe('Base Path', () => { + let page: Page + let url: AdminUrlUtil + let serverURL: string + + test.beforeAll(async ({ browser }, testInfo) => { + testInfo.setTimeout(TEST_TIMEOUT_LONG) + + const { payload } = await initPayloadE2ENoConfig({ + dirname, + }) + serverURL = payload.serverURL + url = new AdminUrlUtil(serverURL, 'posts') + + const context = await browser.newContext() + page = await context.newPage() + initPageConsoleErrorCatch(page) + + await ensureCompilationIsDone({ + page, + serverURL, + }) + }) + + test('should navigate to posts collection by clicking nav link', async () => { + // Navigate to the admin dashboard + await page.goto(url.admin) + + // click first dashboard card + await page.locator('.dashboard__card-list .card').first().click() + + // should navigate to basePath url + await expect.poll(() => page.url()).toContain('/cms/admin/collections/posts') + + await goToListDoc({ + cellClass: '.cell-title', + page, + textToMatch: 'First Post', + urlUtil: url, + }) + + const docID = (await page.locator('.render-title').getAttribute('data-doc-id')) as string + // should navigate to edit view with basePath url + await expect.poll(() => page.url()).toContain(`/cms/admin/collections/posts/${docID}`) + + await page.locator('#field-title').fill('First Post Edited') + await saveDocAndAssert(page) + }) + + test('should navigate to create new post by clicking button', async () => { + // Navigate to posts list + await page.goto(url.list) + + // Click the "Create New" button + const createButton = page.locator('a[href*="/posts/create"]').first() + await expect(createButton).toBeVisible() + await createButton.click() + + // Verify we navigated to the create view + await expect.poll(() => page.url()).toContain('/posts/create') + + // Verify the form is rendered + await expect(page.locator('#field-title')).toBeVisible() + }) +}) diff --git a/test/base-path/next-env.d.ts b/test/base-path/next-env.d.ts new file mode 100644 index 00000000000..1b3be0840f3 --- /dev/null +++ b/test/base-path/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/test/base-path/seed/index.ts b/test/base-path/seed/index.ts new file mode 100644 index 00000000000..d0fd612441a --- /dev/null +++ b/test/base-path/seed/index.ts @@ -0,0 +1,38 @@ +import type { Config } from 'payload' + +import { devUser } from '../../credentials.js' + +export const seed: Config['onInit'] = async (payload) => { + await payload.create({ + collection: 'users', + data: { + email: devUser.email, + password: devUser.password, + }, + }) + + // Seed some sample posts + await payload.create({ + collection: 'posts', + data: { + content: 'This is the content of the first post.', + title: 'First Post', + }, + }) + + await payload.create({ + collection: 'posts', + data: { + content: 'This is the content of the second post.', + title: 'Second Post', + }, + }) + + await payload.create({ + collection: 'posts', + data: { + content: 'This is the content of the third post.', + title: 'Third Post', + }, + }) +} diff --git a/test/base-path/shared.ts b/test/base-path/shared.ts new file mode 100644 index 00000000000..c64e6f68209 --- /dev/null +++ b/test/base-path/shared.ts @@ -0,0 +1 @@ +export const BASE_PATH = '/cms' diff --git a/test/base-path/tsconfig.eslint.json b/test/base-path/tsconfig.eslint.json new file mode 100644 index 00000000000..b31482bef8b --- /dev/null +++ b/test/base-path/tsconfig.eslint.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"] +} diff --git a/test/base-path/tsconfig.json b/test/base-path/tsconfig.json new file mode 100644 index 00000000000..88a05102f38 --- /dev/null +++ b/test/base-path/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@payload-config": ["./config.ts"], + "@payloadcms/ui/assets": ["../../packages/ui/src/assets/index.ts"], + "@payloadcms/ui/elements/*": ["../../packages/ui/src/elements/*/index.tsx"], + "@payloadcms/ui/fields/*": ["../../packages/ui/src/fields/*/index.tsx"], + "@payloadcms/ui/forms/*": ["../../packages/ui/src/forms/*/index.tsx"], + "@payloadcms/ui/graphics/*": ["../../packages/ui/src/graphics/*/index.tsx"], + "@payloadcms/ui/hooks/*": ["../../packages/ui/src/hooks/*.ts"], + "@payloadcms/ui/icons/*": ["../../packages/ui/src/icons/*/index.tsx"], + "@payloadcms/ui/providers/*": ["../../packages/ui/src/providers/*/index.tsx"], + "@payloadcms/ui/templates/*": ["../../packages/ui/src/templates/*/index.tsx"], + "@payloadcms/ui/utilities/*": ["../../packages/ui/src/utilities/*.ts"], + "@payloadcms/ui/scss": ["../../packages/ui/src/scss.scss"], + "@payloadcms/ui/scss/app.scss": ["../../packages/ui/src/scss/app.scss"], + "payload/types": ["../../packages/payload/src/exports/types.ts"], + "@payloadcms/next/*": ["../../packages/next/src/*"], + "@payloadcms/next": ["../../packages/next/src/exports/*"] + } + }, + "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/test/dev.ts b/test/dev.ts index c7c94a779a9..72630509f60 100644 --- a/test/dev.ts +++ b/test/dev.ts @@ -48,7 +48,16 @@ if (!testSuiteArg || !fs.existsSync(path.resolve(dirname, testSuiteArg))) { } // Enable turbopack by default, unless --no-turbo is passed -const enableTurbo = args.turbo !== false +let enableTurbo = args.turbo !== false + +if (['admin-root'].includes(testSuiteArg)) { + console.log( + chalk.yellow( + `The "${testSuiteArg}" test directory is not compatible with turbopack, using webpack instead.`, + ), + ) + enableTurbo = false +} console.log(`Selected test suite: ${testSuiteArg}${enableTurbo ? ' [Turbopack]' : ' [Webpack]'}`) diff --git a/test/field-error-states/e2e.spec.ts b/test/field-error-states/e2e.spec.ts index a0489bc23d2..cf93bbd5246 100644 --- a/test/field-error-states/e2e.spec.ts +++ b/test/field-error-states/e2e.spec.ts @@ -4,10 +4,15 @@ import { expect, test } from '@playwright/test' import { AdminUrlUtil } from 'helpers/adminUrlUtil.js' import { addArrayRow, removeArrayRow } from 'helpers/e2e/fields/array/index.js' import path from 'path' -import { wait } from 'payload/shared' +import { formatAdminURL, wait } from 'payload/shared' import { fileURLToPath } from 'url' -import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js' +import { + ensureCompilationIsDone, + getRoutes, + initPageConsoleErrorCatch, + saveDocAndAssert, +} from '../helpers.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { TEST_TIMEOUT_LONG } from '../playwright.config.js' import { collectionSlugs } from './shared.js' @@ -25,6 +30,7 @@ describe('Field Error States', () => { let prevValue: AdminUrlUtil let prevValueRelation: AdminUrlUtil let errorFieldsURL: AdminUrlUtil + let adminRoute: string beforeAll(async ({ browser }, testInfo) => { testInfo.setTimeout(TEST_TIMEOUT_LONG) @@ -38,6 +44,11 @@ describe('Field Error States', () => { prevValue = new AdminUrlUtil(serverURL, collectionSlugs.prevValue!) prevValueRelation = new AdminUrlUtil(serverURL, collectionSlugs.prevValueRelation!) errorFieldsURL = new AdminUrlUtil(serverURL, collectionSlugs.errorFields!) + + const { + routes: { admin: adminRouteFromConfig }, + } = getRoutes({}) + adminRoute = adminRouteFromConfig const context = await browser.newContext() page = await context.newPage() initPageConsoleErrorCatch(page) @@ -46,7 +57,9 @@ describe('Field Error States', () => { }) test('Remove row should remove error states from parent fields', async () => { - await page.goto(`${serverURL}/admin/collections/error-fields/create`) + await page.goto( + formatAdminURL({ adminRoute, path: '/collections/error-fields/create', serverURL }), + ) // add parent array await addArrayRow(page, { fieldName: 'parentArray' }) diff --git a/test/folders-browse-by-disabled/e2e.spec.ts b/test/folders-browse-by-disabled/e2e.spec.ts index d81a5365467..022be642050 100644 --- a/test/folders-browse-by-disabled/e2e.spec.ts +++ b/test/folders-browse-by-disabled/e2e.spec.ts @@ -3,9 +3,10 @@ import type { Page } from '@playwright/test' import { expect, test } from '@playwright/test' import { reInitializeDB } from 'helpers/reInitializeDB.js' import * as path from 'path' +import { formatAdminURL } from 'payload/shared' import { fileURLToPath } from 'url' -import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { ensureCompilationIsDone, getRoutes, initPageConsoleErrorCatch } from '../helpers.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { TEST_TIMEOUT_LONG } from '../playwright.config.js' @@ -15,6 +16,7 @@ const dirname = path.dirname(filename) test.describe('Browse By Folders Disabled', () => { let page: Page let serverURL: string + let adminRoute: string test.beforeAll(async ({ browser }, testInfo) => { testInfo.setTimeout(TEST_TIMEOUT_LONG) @@ -22,6 +24,11 @@ test.describe('Browse By Folders Disabled', () => { const { serverURL: serverFromInit } = await initPayloadE2ENoConfig({ dirname }) serverURL = serverFromInit + const { + routes: { admin: adminRouteFromConfig }, + } = getRoutes({}) + adminRoute = adminRouteFromConfig + const context = await browser.newContext() page = await context.newPage() initPageConsoleErrorCatch(page) @@ -36,7 +43,7 @@ test.describe('Browse By Folders Disabled', () => { }) test('should not show the browse-by-folder button in the nav', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ adminRoute, path: '', serverURL })) await page.locator('#nav-toggler button.nav-toggler').click() await expect(page.locator('#nav-toggler button.nav-toggler--is-open')).toBeVisible() await expect(page.locator('.browse-by-folder-button')).toBeHidden() diff --git a/test/folders/e2e.spec.ts b/test/folders/e2e.spec.ts index fe1702b3211..b3b7aa740bd 100644 --- a/test/folders/e2e.spec.ts +++ b/test/folders/e2e.spec.ts @@ -2,9 +2,15 @@ import type { Page } from '@playwright/test' import { expect, test } from '@playwright/test' import * as path from 'path' +import { formatAdminURL } from 'payload/shared' import { fileURLToPath } from 'url' -import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js' +import { + ensureCompilationIsDone, + getRoutes, + initPageConsoleErrorCatch, + saveDocAndAssert, +} from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { getSelectInputOptions, @@ -32,6 +38,7 @@ test.describe('Folders', () => { let postURL: AdminUrlUtil let OmittedFromBrowseBy: AdminUrlUtil let serverURL: string + let adminRoute: string test.beforeAll(async ({ browser }, testInfo) => { testInfo.setTimeout(TEST_TIMEOUT_LONG) @@ -41,6 +48,11 @@ test.describe('Folders', () => { postURL = new AdminUrlUtil(serverURL, postSlug) OmittedFromBrowseBy = new AdminUrlUtil(serverURL, omittedFromBrowseBySlug) + const { + routes: { admin: adminRouteFromConfig }, + } = getRoutes({}) + adminRoute = adminRouteFromConfig + const context = await browser.newContext() page = await context.newPage() initPageConsoleErrorCatch(page) @@ -56,7 +68,7 @@ test.describe('Folders', () => { test.describe('No folders', () => { test('should show no results and create button in folder view', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await expectNoResultsAndCreateFolderButton({ page }) }) @@ -71,7 +83,7 @@ test.describe('Folders', () => { test.describe('Creating folders', () => { test('should create new folder from folder view', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'New Folder From Root', page }) }) @@ -91,13 +103,13 @@ test.describe('Folders', () => { test.describe('Folder view actions', () => { test('should show Browse by Folder button', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ adminRoute, path: '', serverURL })) const folderButton = page.locator('text=Browse by folder') await expect(folderButton).toBeVisible() }) test('should rename folder', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Test Folder', page }) await clickFolderCard({ folderName: 'Test Folder', page }) const editFolderDocButton = page.locator('.list-selection__actions button', { @@ -119,7 +131,7 @@ test.describe('Folders', () => { }) test('should delete folder', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Delete This Folder', page }) await clickFolderCard({ folderName: 'Delete This Folder', page }) const deleteButton = page.locator('.list-selection__actions button', { @@ -136,12 +148,12 @@ test.describe('Folders', () => { }) test('should delete folder but not delete documents', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Folder With Documents', page }) await createPostWithExistingFolder('Document 1', 'Folder With Documents') await createPostWithExistingFolder('Document 2', 'Folder With Documents') - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await clickFolderCard({ folderName: 'Folder With Documents', page }) const deleteButton = page.locator('.list-selection__actions button', { hasText: 'Delete', @@ -163,7 +175,7 @@ test.describe('Folders', () => { }) test('should move folder', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Move Into This Folder', page }) await createFolder({ folderName: 'Move Me', page }) await clickFolderCard({ folderName: 'Move Me', page }) @@ -194,7 +206,7 @@ test.describe('Folders', () => { // this test currently fails in postgres test('should create new document from folder', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Create New Here', page, @@ -225,7 +237,7 @@ test.describe('Folders', () => { }) test('should create nested folder from folder view', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Parent Folder', page }) await clickFolderCard({ folderName: 'Parent Folder', page, doubleClick: true }) const pageTitle = page.locator('h1.list-header__title') @@ -248,7 +260,7 @@ test.describe('Folders', () => { }) test('should toggle between grid and list view', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Test Folder', page }) const listViewButton = page.locator('.folder-view-toggle-button').nth(1) await listViewButton.click() @@ -262,7 +274,7 @@ test.describe('Folders', () => { }) test('should sort folders', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'A Folder', page }) await createFolder({ folderName: 'B Folder', page }) await createFolder({ folderName: 'C Folder', page }) @@ -282,7 +294,7 @@ test.describe('Folders', () => { }) test('should allow filtering within folders', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Filtering Folder', page }) await clickFolderCard({ folderName: 'Filtering Folder', page, doubleClick: true }) @@ -339,7 +351,7 @@ test.describe('Folders', () => { }) test('should allow searching within folders', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Test', page }) await createFolder({ folderName: 'Search Me', page }) @@ -362,7 +374,7 @@ test.describe('Folders', () => { test.describe('Collection view actions', () => { test.beforeEach(async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Move Into This Folder', page }) await createPostWithNoFolder() await page.goto(postURL.list) @@ -375,7 +387,9 @@ test.describe('Folders', () => { test('should navigate to By Folder view', async () => { const folderButton = page.locator('.default-list-view-tabs__button', { hasText: 'By Folder' }) await folderButton.click() - await expect(page).toHaveURL(`${serverURL}/admin/collections/posts/payload-folders`) + await expect(page).toHaveURL( + formatAdminURL({ adminRoute, path: '/collections/posts/payload-folders', serverURL }), + ) const foldersTitle = page.locator('.collection-folder-list', { hasText: 'Folders' }) await expect(foldersTitle).toBeVisible() }) @@ -439,7 +453,7 @@ test.describe('Folders', () => { test.describe('Document view actions', () => { test.beforeEach(async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Test Folder', page }) await createPostWithNoFolder() }) @@ -506,7 +520,7 @@ test.describe('Folders', () => { await saveDocAndAssert(page) // go to browse by folder view - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await clickFolderCard({ folderName, page, doubleClick: true }) // folder should be empty @@ -515,7 +529,7 @@ test.describe('Folders', () => { test('should not show collection type in browse by folder view', async () => { const folderName = 'omitted collection pill test folder' - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName, page }) await clickFolderCard({ folderName, page, doubleClick: true }) @@ -531,7 +545,7 @@ test.describe('Folders', () => { test.describe('Multiple select options', () => { test.beforeEach(async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Test Folder 1', page }) await createFolder({ folderName: 'Test Folder 2', page }) await createFolder({ folderName: 'Test Folder 3', page }) @@ -606,7 +620,7 @@ test.describe('Folders', () => { test.describe('should inherit folderType select values from parent folder', () => { test('should scope folderType select options for: scoped > child folder', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'Posts and Media', page, folderType: ['Posts', 'Media'] }) await clickFolderCard({ folderName: 'Posts and Media', page, doubleClick: true }) @@ -641,7 +655,7 @@ test.describe('Folders', () => { }) test('should scope folderType select options for: unscoped > scoped > child folder', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) // create an unscoped parent folder await createFolder({ folderName: 'All collections', page, folderType: [] }) @@ -699,7 +713,7 @@ test.describe('Folders', () => { }) test('should not scope child folder of an unscoped parent folder', async () => { - await page.goto(`${serverURL}/admin/browse-by-folder`) + await page.goto(formatAdminURL({ adminRoute, path: '/browse-by-folder', serverURL })) await createFolder({ folderName: 'All collections', page, folderType: [] }) await clickFolderCard({ folderName: 'All collections', page, doubleClick: true }) diff --git a/test/form-state/e2e.spec.ts b/test/form-state/e2e.spec.ts index 73904cd7738..cd9d464367d 100644 --- a/test/form-state/e2e.spec.ts +++ b/test/form-state/e2e.spec.ts @@ -1,25 +1,13 @@ import type { BrowserContext, CDPSession, Page } from '@playwright/test' -import type { PayloadTestSDK } from 'helpers/sdk/index.js' import type { FormState } from 'payload' import { expect, test } from '@playwright/test' -import { postSlug } from 'folders/shared.js' -import { assertElementStaysVisible } from 'helpers/e2e/assertElementStaysVisible.js' -import { assertNetworkRequests } from 'helpers/e2e/assertNetworkRequests.js' -import { assertRequestBody } from 'helpers/e2e/assertRequestBody.js' -import { - addArrayRow, - addArrayRowAsync, - duplicateArrayRow, - removeArrayRow, -} from 'helpers/e2e/fields/array/index.js' -import { addBlock } from 'helpers/e2e/fields/blocks/index.js' -import { waitForAutoSaveToRunAndComplete } from 'helpers/e2e/waitForAutoSaveToRunAndComplete.js' import * as path from 'path' -import { wait } from 'payload/shared' +import { formatAdminURL, wait } from 'payload/shared' import { fileURLToPath } from 'url' -import type { AutosavePost, Config, Post } from './payload-types.js' +import type { PayloadTestSDK } from '../helpers/sdk/index.js' +import type { Config, Post } from './payload-types.js' import { ensureCompilationIsDone, @@ -28,6 +16,17 @@ import { throttleTest, } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' +import { assertElementStaysVisible } from '../helpers/e2e/assertElementStaysVisible.js' +import { assertNetworkRequests } from '../helpers/e2e/assertNetworkRequests.js' +import { assertRequestBody } from '../helpers/e2e/assertRequestBody.js' +import { + addArrayRow, + addArrayRowAsync, + duplicateArrayRow, + removeArrayRow, +} from '../helpers/e2e/fields/array/index.js' +import { addBlock } from '../helpers/e2e/fields/blocks/index.js' +import { waitForAutoSaveToRunAndComplete } from '../helpers/e2e/waitForAutoSaveToRunAndComplete.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { TEST_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js' import { autosavePostsSlug } from './collections/Autosave/index.js' @@ -175,7 +174,7 @@ test.describe('Form State', () => { expect: (body) => Boolean( body?.[0]?.args?.formState?.['array'] && - body[0].args.formState['array'].lastRenderedPath === 'array', + body[0].args.formState['array'].lastRenderedPath === 'array', ), }) @@ -194,9 +193,9 @@ test.describe('Form State', () => { expect: (body) => Boolean( body?.[0]?.args?.formState?.['array'] && - body[0].args.formState['array'].lastRenderedPath === 'array' && - body[0].args.formState['array.0.customTextField']?.lastRenderedPath === - 'array.0.customTextField', + body[0].args.formState['array'].lastRenderedPath === 'array' && + body[0].args.formState['array.0.customTextField']?.lastRenderedPath === + 'array.0.customTextField', ), }) @@ -216,11 +215,11 @@ test.describe('Form State', () => { expect: (body) => Boolean( body?.[0]?.args?.formState?.['array'] && - body[0].args.formState['array'].lastRenderedPath && - body[0].args.formState['array.0.customTextField']?.lastRenderedPath === - 'array.0.customTextField' && - body[0].args.formState['array.1.customTextField']?.lastRenderedPath === - 'array.1.customTextField', + body[0].args.formState['array'].lastRenderedPath && + body[0].args.formState['array.0.customTextField']?.lastRenderedPath === + 'array.0.customTextField' && + body[0].args.formState['array.1.customTextField']?.lastRenderedPath === + 'array.1.customTextField', ), }) }) @@ -341,7 +340,7 @@ test.describe('Form State', () => { await assertNetworkRequests( page, - `${serverURL}/api/posts/access/${doc.id}`, + formatAdminURL({ apiRoute: '/api', path: `/posts/access/${doc.id}`, serverURL }), async () => { await titleField.fill('Updated Title') await wait(500) @@ -356,7 +355,7 @@ test.describe('Form State', () => { await assertNetworkRequests( page, - `${serverURL}/api/posts/access/${doc.id}`, + formatAdminURL({ apiRoute: '/api', path: `/posts/access/${doc.id}`, serverURL }), async () => { await titleField.fill('Updated Title 2') await wait(500) @@ -384,7 +383,11 @@ test.describe('Form State', () => { await assertNetworkRequests( page, - `${serverURL}/api/${autosavePostsSlug}/access/${doc.id}`, + formatAdminURL({ + apiRoute: '/api', + path: `/${autosavePostsSlug}/access/${doc.id}`, + serverURL, + }), async () => { await titleField.fill('Updated Title') }, @@ -396,7 +399,11 @@ test.describe('Form State', () => { await assertNetworkRequests( page, - `${serverURL}/api/${autosavePostsSlug}/access/${doc.id}`, + formatAdminURL({ + apiRoute: '/api', + path: `/${autosavePostsSlug}/access/${doc.id}`, + serverURL, + }), async () => { await titleField.fill('Updated Title Again') }, @@ -409,7 +416,11 @@ test.describe('Form State', () => { // save manually and ensure the permissions are fetched again await assertNetworkRequests( page, - `${serverURL}/api/${autosavePostsSlug}/access/${doc.id}`, + formatAdminURL({ + apiRoute: '/api', + path: `/${autosavePostsSlug}/access/${doc.id}`, + serverURL, + }), async () => { await page.click('#action-save', { delay: 100 }) }, diff --git a/test/helpers.ts b/test/helpers.ts index ca09157849b..a4ea5f27d00 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -5,17 +5,17 @@ import type { Locator, Page, } from '@playwright/test' -import type { Config } from 'payload' +import type { Config, SanitizedConfig } from 'payload' import { expect } from '@playwright/test' import { defaults } from 'payload' -import { wait } from 'payload/shared' +import { formatAdminURL, wait } from 'payload/shared' import shelljs from 'shelljs' import { setTimeout } from 'timers/promises' import { POLL_TOPASS_TIMEOUT } from './playwright.config.js' -export type AdminRoutes = NonNullable['routes'] +export type AdminRoutes = NonNullable['routes']> const random = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min @@ -69,7 +69,7 @@ export async function ensureCompilationIsDone({ }): Promise { const { routes: { admin: adminRoute } = {} } = getRoutes({ customAdminRoutes, customRoutes }) - const adminURL = `${serverURL}${adminRoute}` + const adminURL = formatAdminURL({ adminRoute, path: '', serverURL }) const maxAttempts = 50 let attempt = 1 @@ -425,7 +425,7 @@ export function getRoutes({ admin: { routes: AdminRoutes } - routes: Config['routes'] + routes: NonNullable } { let routes = defaults.routes let adminRoutes = defaults.admin?.routes diff --git a/test/helpers/e2e/auth/login.ts b/test/helpers/e2e/auth/login.ts index e4994335750..0bf8e591bfa 100644 --- a/test/helpers/e2e/auth/login.ts +++ b/test/helpers/e2e/auth/login.ts @@ -1,13 +1,14 @@ -import type { AdminRoutes } from 'helpers.js' import type { Config } from 'payload' import type { Page } from 'playwright/test' -import { devUser } from 'credentials.js' -import { getRoutes } from 'helpers.js' import { formatAdminURL, wait } from 'payload/shared' -import { POLL_TOPASS_TIMEOUT } from 'playwright.config.js' import { expect } from 'playwright/test' +import type { AdminRoutes } from '../../../helpers.js' + +import { devUser } from '../../../credentials.js' +import { getRoutes } from '../../../helpers.js' +import { POLL_TOPASS_TIMEOUT } from '../../../playwright.config.js' import { openNav } from '../toggleNav.js' type LoginArgs = { diff --git a/test/helpers/e2e/auth/logout.ts b/test/helpers/e2e/auth/logout.ts index 0b87fee7764..1b455969c20 100644 --- a/test/helpers/e2e/auth/logout.ts +++ b/test/helpers/e2e/auth/logout.ts @@ -1,12 +1,17 @@ import type { Page } from 'playwright' +import { getRoutes } from 'helpers.js' +import { formatAdminURL } from 'payload/shared' import { POLL_TOPASS_TIMEOUT } from 'playwright.config.js' import { expect } from 'playwright/test' import { openNav } from '../toggleNav.js' export const logout = async (page: Page, serverURL: string) => { - await page.goto(`${serverURL}/admin/logout`) + const { + routes: { admin: adminRoute }, + } = getRoutes({}) + await page.goto(formatAdminURL({ adminRoute, path: '/logout', serverURL })) await expect.poll(() => page.url(), { timeout: POLL_TOPASS_TIMEOUT }).toContain('/admin/login') diff --git a/test/helpers/e2e/goToListDoc.ts b/test/helpers/e2e/goToListDoc.ts index 3212d1fec10..3bb93116ec2 100644 --- a/test/helpers/e2e/goToListDoc.ts +++ b/test/helpers/e2e/goToListDoc.ts @@ -1,5 +1,7 @@ import type { Page } from '@playwright/test' +import { formatAdminURL } from 'payload/shared' + import type { AdminUrlUtil } from '../../helpers/adminUrlUtil.js' import { getRowByCellValueAndAssert } from './getRowByCellValueAndAssert.js' @@ -8,8 +10,10 @@ export async function goToListDoc({ page, cellClass, textToMatch, + adminRoute = '/admin', urlUtil, }: { + adminRoute?: `/${string}` cellClass: `.cell-${string}` page: Page textToMatch: string @@ -19,6 +23,19 @@ export async function goToListDoc({ const row = await getRowByCellValueAndAssert({ page, textToMatch, cellClass }) const cellLink = row.locator(`td a`).first() const linkURL = await cellLink.getAttribute('href') - await page.goto(`${urlUtil.serverURL}${linkURL}`) + + // Ensure we always have a full URL + let fullURL: string + if (!linkURL) { + fullURL = formatAdminURL({ adminRoute, serverURL: urlUtil.serverURL, path: '' }) + } else if (linkURL.startsWith('http://') || linkURL.startsWith('https://')) { + // Already absolute + fullURL = linkURL + } else { + // Relative URL - prepend serverURL + fullURL = `${urlUtil.serverURL}${linkURL}` + } + + await page.goto(fullURL) await page.waitForLoadState('networkidle') } diff --git a/test/helpers/reInitializeDB.ts b/test/helpers/reInitializeDB.ts index 110b71b80d4..c880c399c29 100644 --- a/test/helpers/reInitializeDB.ts +++ b/test/helpers/reInitializeDB.ts @@ -1,3 +1,4 @@ +import { formatAdminURL } from 'payload/shared' import * as qs from 'qs-esm' export const path = '/re-initialize' @@ -32,12 +33,15 @@ export const reInitializeDB = async ({ }, ) - const response = await fetch(`${serverURL}/api${path}${queryParams}`, { - method: 'get', - headers: { - 'Content-Type': 'application/json', + const response = await fetch( + formatAdminURL({ apiRoute: '/api', path: `${path}${queryParams}`, serverURL }), + { + method: 'get', + headers: { + 'Content-Type': 'application/json', + }, }, - }) + ) if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`) diff --git a/test/helpers/sdk/index.ts b/test/helpers/sdk/index.ts index 2c5cfb280ea..fd357525b2b 100644 --- a/test/helpers/sdk/index.ts +++ b/test/helpers/sdk/index.ts @@ -1,5 +1,7 @@ import type { PaginatedDocs, SendEmailOptions } from 'payload' +import { formatAdminURL } from 'payload/shared' + import type { CreateArgs, DeleteArgs, @@ -25,14 +27,21 @@ export class PayloadTestSDK res.json()) + { + method: 'post', + headers, + body: JSON.stringify({ + args, + operation, + }), + }, + ).then((res) => res.json()) if (reduceJSON) { return reduceJSON(json) diff --git a/test/lexical/collections/Lexical/LexicalRendered.tsx b/test/lexical/collections/Lexical/LexicalRendered.tsx index 4d49066e56e..35c34da9a2c 100644 --- a/test/lexical/collections/Lexical/LexicalRendered.tsx +++ b/test/lexical/collections/Lexical/LexicalRendered.tsx @@ -13,6 +13,7 @@ import { } from '@payloadcms/richtext-lexical/html-async' import { type JSXConvertersFunction, RichText } from '@payloadcms/richtext-lexical/react' import { useConfig, useDocumentInfo, usePayloadAPI } from '@payloadcms/ui' +import { formatAdminURL } from 'payload/shared' import React, { useEffect, useMemo, useState } from 'react' const jsxConverters: JSXConvertersFunction> = ({ @@ -61,17 +62,23 @@ export const LexicalRendered: React.FC = () => { }, } = useConfig() - const [{ data }] = usePayloadAPI(`${serverURL}${api}/${collectionSlug}/${id}`, { - initialParams: { - depth: 1, + const [{ data }] = usePayloadAPI( + formatAdminURL({ apiRoute: api, path: `/${collectionSlug}/${id}`, serverURL }), + { + initialParams: { + depth: 1, + }, }, - }) + ) - const [{ data: unpopulatedData }] = usePayloadAPI(`${serverURL}${api}/${collectionSlug}/${id}`, { - initialParams: { - depth: 0, + const [{ data: unpopulatedData }] = usePayloadAPI( + formatAdminURL({ apiRoute: api, path: `/${collectionSlug}/${id}`, serverURL }), + { + initialParams: { + depth: 0, + }, }, - }) + ) const html: null | string = useMemo(() => { if (!data.lexicalWithBlocks) { @@ -92,7 +99,7 @@ export const LexicalRendered: React.FC = () => { converters: htmlConvertersAsync, data: unpopulatedData.lexicalWithBlocks as SerializedEditorState, populate: getRestPopulateFn({ - apiURL: `${serverURL}${api}`, + apiURL: formatAdminURL({ apiRoute: api, path: '', serverURL }), }), }) diff --git a/test/localization/e2e.spec.ts b/test/localization/e2e.spec.ts index c3b7297578f..5a54d3f383a 100644 --- a/test/localization/e2e.spec.ts +++ b/test/localization/e2e.spec.ts @@ -12,6 +12,7 @@ import { openDocDrawer } from 'helpers/e2e/toggleDocDrawer.js' import { waitForAutoSaveToRunAndComplete } from 'helpers/e2e/waitForAutoSaveToRunAndComplete.js' import { RESTClient } from 'helpers/rest.js' import path from 'path' +import { formatAdminURL } from 'payload/shared' import { fileURLToPath } from 'url' import type { PayloadTestSDK } from '../helpers/sdk/index.js' @@ -634,7 +635,11 @@ describe('Localization', () => { await saveDocAndAssert(page) const id = page.url().split('/').pop() - const apiURL = `${serverURL}/api/${arrayWithFallbackCollectionSlug}/${id}` + const apiURL = formatAdminURL({ + apiRoute: '/api', + path: `/${arrayWithFallbackCollectionSlug}/${id}`, + serverURL, + }) await page.goto(apiURL) const data = await page.evaluate(() => { return JSON.parse(document.querySelector('body')?.innerText || '{}') diff --git a/test/server-functions/e2e.spec.ts b/test/server-functions/e2e.spec.ts index 1c05657c94c..d8b723136aa 100644 --- a/test/server-functions/e2e.spec.ts +++ b/test/server-functions/e2e.spec.ts @@ -3,12 +3,13 @@ import type { Page } from '@playwright/test' import { expect, test } from '@playwright/test' import { devUser } from 'credentials.js' import path from 'path' +import { formatAdminURL } from 'payload/shared' import { fileURLToPath } from 'url' import type { PayloadTestSDK } from '../helpers/sdk/index.js' import type { Config } from './payload-types.js' -import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { ensureCompilationIsDone, getRoutes, initPageConsoleErrorCatch } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { TEST_TIMEOUT_LONG } from '../playwright.config.js' @@ -24,12 +25,18 @@ describe('Server Functions', () => { let page: Page let url: AdminUrlUtil let serverURL: string + let adminRoute: string beforeAll(async ({ browser }, testInfo) => { testInfo.setTimeout(TEST_TIMEOUT_LONG) ;({ payload, serverURL } = await initPayloadE2ENoConfig({ dirname })) url = new AdminUrlUtil(serverURL, 'users') + const { + routes: { admin: adminRouteFromConfig }, + } = getRoutes({}) + adminRoute = adminRouteFromConfig + const context = await browser.newContext() page = await context.newPage() initPageConsoleErrorCatch(page) @@ -43,7 +50,7 @@ describe('Server Functions', () => { describe('Auth functions', () => { test('should log user in from login server function', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ adminRoute, path: '', serverURL })) // Expect email and password fields to be visible await expect(page.locator('#email')).toBeVisible() @@ -58,12 +65,12 @@ describe('Server Functions', () => { await page.waitForTimeout(1000) await page.reload() - await page.goto(`${serverURL}/admin/account`) + await page.goto(formatAdminURL({ adminRoute, path: '/account', serverURL })) await expect(page.locator('h1[title="dev@payloadcms.com"]')).toBeVisible() }) test('should refresh user from refresh server function', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ adminRoute, path: '', serverURL })) const initialCookie = await page.context().cookies() const payloadToken = initialCookie.find((cookie) => cookie.name === 'payload-token') @@ -82,14 +89,14 @@ describe('Server Functions', () => { }) test('should log user out from logout server function', async () => { - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ adminRoute, path: '', serverURL })) const logoutButton = page.locator('text=Custom Logout') await expect(logoutButton).toBeVisible() await logoutButton.click() await page.waitForTimeout(1000) await page.reload() - await page.goto(`${serverURL}/admin`) + await page.goto(formatAdminURL({ adminRoute, path: '', serverURL })) await expect(page.locator('#email')).toBeVisible() await expect(page.locator('#password')).toBeVisible() }) diff --git a/test/server-url/e2e.spec.ts b/test/server-url/e2e.spec.ts index f576bbb223a..fb495eca204 100644 --- a/test/server-url/e2e.spec.ts +++ b/test/server-url/e2e.spec.ts @@ -3,7 +3,6 @@ import type { Page } from '@playwright/test' import { expect, test } from '@playwright/test' import { login } from 'helpers/e2e/auth/login.js' import { logoutViaNav } from 'helpers/e2e/auth/logout.js' -import { openNav } from 'helpers/e2e/toggleNav.js' import * as path from 'path' import { fileURLToPath } from 'url' diff --git a/test/versions/config.ts b/test/versions/config.ts index 2b5aede3237..5efe626f96f 100644 --- a/test/versions/config.ts +++ b/test/versions/config.ts @@ -31,7 +31,8 @@ import DraftWithMaxGlobal from './globals/DraftWithMax.js' import LocalizedGlobal from './globals/LocalizedGlobal.js' import { MaxVersions } from './globals/MaxVersions.js' import { seed } from './seed.js' - +import { BASE_PATH } from './shared.js' +process.env.NEXT_BASE_PATH = BASE_PATH export default buildConfigWithDefaults({ admin: { importMap: { diff --git a/test/versions/e2e.spec.ts b/test/versions/e2e.spec.ts index 138a17a4eef..4ef054a5613 100644 --- a/test/versions/e2e.spec.ts +++ b/test/versions/e2e.spec.ts @@ -30,7 +30,7 @@ import { checkFocusIndicators } from 'helpers/e2e/checkFocusIndicators.js' import { runAxeScan } from 'helpers/e2e/runAxeScan.js' import mongoose from 'mongoose' import path from 'path' -import { wait } from 'payload/shared' +import { formatAdminURL, wait } from 'payload/shared' import { fileURLToPath } from 'url' import type { PayloadTestSDK } from '../helpers/sdk/index.js' @@ -40,6 +40,7 @@ import { changeLocale, ensureCompilationIsDone, exactText, + getRoutes, initPageConsoleErrorCatch, openDocDrawer, saveDocAndAssert, @@ -51,6 +52,7 @@ import { waitForAutoSaveToRunAndComplete } from '../helpers/e2e/waitForAutoSaveT import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { reInitializeDB } from '../helpers/reInitializeDB.js' import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js' +import { BASE_PATH } from './shared.js' import { autosaveCollectionSlug, autoSaveGlobalSlug, @@ -76,6 +78,7 @@ import { const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) +process.env.NEXT_BASE_PATH = BASE_PATH const { beforeAll, beforeEach, describe } = test @@ -98,6 +101,7 @@ describe('Versions', () => { let postURL: AdminUrlUtil let errorOnUnpublishURL: AdminUrlUtil let draftsNoReadVersionsURL: AdminUrlUtil + let adminRoute: string beforeAll(async ({ browser }, testInfo) => { testInfo.setTimeout(TEST_TIMEOUT_LONG) @@ -107,6 +111,11 @@ describe('Versions', () => { context = await browser.newContext() page = await context.newPage() + const { + routes: { admin: adminRouteFromConfig }, + } = getRoutes({}) + adminRoute = adminRouteFromConfig + initPageConsoleErrorCatch(page) await ensureCompilationIsDone({ page, serverURL }) }) @@ -236,17 +245,7 @@ describe('Versions', () => { await titleField.fill('test') await descriptionField.fill('test') - const createdDate = await page.textContent( - 'li:has(p:has-text("Created:")) .doc-controls__value', - ) - - // wait for modified date and created date to be different - await expect(async () => { - const modifiedDateLocator = page.locator( - 'li:has(p:has-text("Last Modified:")) .doc-controls__value', - ) - await expect(modifiedDateLocator).not.toHaveText(createdDate ?? '') - }).toPass({ timeout: POLL_TOPASS_TIMEOUT, intervals: [100] }) + await waitForAutoSaveToRunAndComplete(page) const closeDrawer = page.locator('.doc-drawer__header-close') await closeDrawer.click() @@ -450,7 +449,11 @@ describe('Versions', () => { await assertNetworkRequests( page, - `${serverURL}/admin/collections/${postCollectionSlug}/${postID}`, + formatAdminURL({ + adminRoute, + path: `/collections/${postCollectionSlug}/${postID}`, + serverURL, + }), async () => { await page .locator( @@ -495,7 +498,11 @@ describe('Versions', () => { await assertNetworkRequests( page, // Important: assert that depth is 0 in this request - `${serverURL}/api/autosave-posts/${docID}?depth=0&draft=true&autosave=true&locale=en&fallback-locale=null`, + formatAdminURL({ + apiRoute: '/api', + path: `/autosave-posts/${docID}?autosave=true&depth=0&draft=true&fallback-locale=null&locale=en`, + serverURL, + }), async () => { await page.locator('#field-title').fill('changed title') }, @@ -1780,13 +1787,21 @@ describe('Versions', () => { }) async function navigateToDraftVersionView(versionID: string) { - const versionURL = `${serverURL}/admin/collections/${draftCollectionSlug}/${postID}/versions/${versionID}` + const versionURL = formatAdminURL({ + adminRoute, + path: `/collections/${draftCollectionSlug}/${postID}/versions/${versionID}`, + serverURL, + }) await page.goto(versionURL) await expect(page.locator('.render-field-diffs').first()).toBeVisible() } async function navigateToDiffVersionView(versionID?: string) { - const versionURL = `${serverURL}/admin/collections/${diffCollectionSlug}/${diffID}/versions/${versionID ?? versionDiffID}` + const versionURL = formatAdminURL({ + adminRoute, + path: `/collections/${diffCollectionSlug}/${diffID}/versions/${versionID ?? versionDiffID}`, + serverURL, + }) await page.goto(versionURL) await expect(page.locator('.render-field-diffs').first()).toBeVisible() } @@ -2414,7 +2429,13 @@ describe('Versions', () => { }, }) - await page.goto(`${serverURL}/admin/collections/${draftCollectionSlug}/${post.id}`) + await page.goto( + formatAdminURL({ + adminRoute, + path: `/collections/${draftCollectionSlug}/${post.id}`, + serverURL, + }), + ) const publishDropdown = page.locator('.doc-controls__controls .popup-button') await publishDropdown.click() diff --git a/test/versions/shared.ts b/test/versions/shared.ts index e69de29bb2d..9ed786de650 100644 --- a/test/versions/shared.ts +++ b/test/versions/shared.ts @@ -0,0 +1 @@ +export const BASE_PATH: '' | `/${string}` = '' diff --git a/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md b/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md index 19d39d0061b..416e89e25d9 100644 --- a/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md +++ b/tools/claude-plugin/skills/payload/reference/PLUGIN-DEVELOPMENT.md @@ -516,13 +516,19 @@ export const myPlugin = 'use client' import { useConfig } from '@payloadcms/ui' import { useEffect, useState } from 'react' +import { formatAdminURL } from 'payload/shared' export const BeforeDashboardClient = () => { const { config } = useConfig() const [data, setData] = useState('') useEffect(() => { - fetch(`${config.serverURL}${config.routes.api}/my-endpoint`) + fetch( + formatAdminURL({ + apiRoute: config.routes.api, + path: '/my-endpoint', + }), + ) .then((res) => res.json()) .then(setData) }, [config.serverURL, config.routes.api]) diff --git a/tsconfig.base.json b/tsconfig.base.json index 71831b45536..c79d70dc84f 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -21,15 +21,8 @@ "skipLibCheck": true, "emitDeclarationOnly": true, "sourceMap": true, - "lib": [ - "DOM", - "DOM.Iterable", - "ES2022" - ], - "types": [ - "node", - "jest" - ], + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "types": ["node", "jest"], "incremental": true, "isolatedModules": true, "plugins": [ @@ -38,84 +31,40 @@ } ], "paths": { - "@payload-config": [ - "./test/admin/config.ts" - ], - "@payloadcms/admin-bar": [ - "./packages/admin-bar/src" - ], - "@payloadcms/live-preview": [ - "./packages/live-preview/src" - ], - "@payloadcms/live-preview-react": [ - "./packages/live-preview-react/src/index.ts" - ], - "@payloadcms/live-preview-vue": [ - "./packages/live-preview-vue/src/index.ts" - ], - "@payloadcms/ui": [ - "./packages/ui/src/exports/client/index.ts" - ], - "@payloadcms/ui/shared": [ - "./packages/ui/src/exports/shared/index.ts" - ], - "@payloadcms/ui/rsc": [ - "./packages/ui/src/exports/rsc/index.ts" - ], - "@payloadcms/ui/scss": [ - "./packages/ui/src/scss.scss" - ], - "@payloadcms/ui/scss/app.scss": [ - "./packages/ui/src/scss/app.scss" - ], - "@payloadcms/next/*": [ - "./packages/next/src/exports/*.ts" - ], + "@payload-config": ["./test/_community/config.ts"], + "@payloadcms/admin-bar": ["./packages/admin-bar/src"], + "@payloadcms/live-preview": ["./packages/live-preview/src"], + "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"], + "@payloadcms/live-preview-vue": ["./packages/live-preview-vue/src/index.ts"], + "@payloadcms/ui": ["./packages/ui/src/exports/client/index.ts"], + "@payloadcms/ui/shared": ["./packages/ui/src/exports/shared/index.ts"], + "@payloadcms/ui/rsc": ["./packages/ui/src/exports/rsc/index.ts"], + "@payloadcms/ui/scss": ["./packages/ui/src/scss.scss"], + "@payloadcms/ui/scss/app.scss": ["./packages/ui/src/scss/app.scss"], + "@payloadcms/next/*": ["./packages/next/src/exports/*.ts"], "@payloadcms/richtext-lexical/client": [ "./packages/richtext-lexical/src/exports/client/index.ts" ], - "@payloadcms/richtext-lexical/rsc": [ - "./packages/richtext-lexical/src/exports/server/rsc.ts" - ], - "@payloadcms/richtext-slate/rsc": [ - "./packages/richtext-slate/src/exports/server/rsc.ts" - ], - "@payloadcms/plugin-ecommerce/ui": [ - "./packages/plugin-ecommerce/src/exports/ui.ts" - ], - "@payloadcms/plugin-ecommerce/react": [ - "./packages/plugin-ecommerce/src/exports/react.ts" - ], - "@payloadcms/plugin-ecommerce/types": [ - "./packages/plugin-ecommerce/src/exports/types.ts" - ], + "@payloadcms/richtext-lexical/rsc": ["./packages/richtext-lexical/src/exports/server/rsc.ts"], + "@payloadcms/richtext-slate/rsc": ["./packages/richtext-slate/src/exports/server/rsc.ts"], + "@payloadcms/plugin-ecommerce/ui": ["./packages/plugin-ecommerce/src/exports/ui.ts"], + "@payloadcms/plugin-ecommerce/react": ["./packages/plugin-ecommerce/src/exports/react.ts"], + "@payloadcms/plugin-ecommerce/types": ["./packages/plugin-ecommerce/src/exports/types.ts"], "@payloadcms/richtext-slate/client": [ "./packages/richtext-slate/src/exports/client/index.ts" ], - "@payloadcms/plugin-seo/client": [ - "./packages/plugin-seo/src/exports/client.ts" - ], - "@payloadcms/plugin-sentry/client": [ - "./packages/plugin-sentry/src/exports/client.ts" - ], - "@payloadcms/plugin-stripe/client": [ - "./packages/plugin-stripe/src/exports/client.ts" - ], - "@payloadcms/plugin-search/client": [ - "./packages/plugin-search/src/exports/client.ts" - ], + "@payloadcms/plugin-seo/client": ["./packages/plugin-seo/src/exports/client.ts"], + "@payloadcms/plugin-sentry/client": ["./packages/plugin-sentry/src/exports/client.ts"], + "@payloadcms/plugin-stripe/client": ["./packages/plugin-stripe/src/exports/client.ts"], + "@payloadcms/plugin-search/client": ["./packages/plugin-search/src/exports/client.ts"], "@payloadcms/plugin-form-builder/client": [ "./packages/plugin-form-builder/src/exports/client.ts" ], "@payloadcms/plugin-import-export/rsc": [ "./packages/plugin-import-export/src/exports/rsc.ts" ], - "@payloadcms/plugin-mcp": [ - "./packages/plugin-mcp/src/index.ts" - ], - "@payloadcms/plugin-multi-tenant/rsc": [ - "./packages/plugin-multi-tenant/src/exports/rsc.ts" - ], + "@payloadcms/plugin-mcp": ["./packages/plugin-mcp/src/index.ts"], + "@payloadcms/plugin-multi-tenant/rsc": ["./packages/plugin-multi-tenant/src/exports/rsc.ts"], "@payloadcms/plugin-multi-tenant/utilities": [ "./packages/plugin-multi-tenant/src/exports/utilities.ts" ], @@ -125,42 +74,25 @@ "@payloadcms/plugin-multi-tenant/client": [ "./packages/plugin-multi-tenant/src/exports/client.ts" ], - "@payloadcms/plugin-multi-tenant": [ - "./packages/plugin-multi-tenant/src/index.ts" - ], + "@payloadcms/plugin-multi-tenant": ["./packages/plugin-multi-tenant/src/index.ts"], "@payloadcms/plugin-multi-tenant/translations/languages/all": [ "./packages/plugin-multi-tenant/src/translations/index.ts" ], "@payloadcms/plugin-multi-tenant/translations/languages/*": [ "./packages/plugin-multi-tenant/src/translations/languages/*.ts" ], - "@payloadcms/next": [ - "./packages/next/src/exports/*" - ], - "@payloadcms/storage-azure/client": [ - "./packages/storage-azure/src/exports/client.ts" - ], - "@payloadcms/storage-s3/client": [ - "./packages/storage-s3/src/exports/client.ts" - ], + "@payloadcms/next": ["./packages/next/src/exports/*"], + "@payloadcms/storage-azure/client": ["./packages/storage-azure/src/exports/client.ts"], + "@payloadcms/storage-s3/client": ["./packages/storage-s3/src/exports/client.ts"], "@payloadcms/storage-vercel-blob/client": [ "./packages/storage-vercel-blob/src/exports/client.ts" ], - "@payloadcms/storage-gcs/client": [ - "./packages/storage-gcs/src/exports/client.ts" - ], + "@payloadcms/storage-gcs/client": ["./packages/storage-gcs/src/exports/client.ts"], "@payloadcms/storage-uploadthing/client": [ "./packages/storage-uploadthing/src/exports/client.ts" ] } }, - "include": [ - "${configDir}/src" - ], - "exclude": [ - "${configDir}/dist", - "${configDir}/build", - "${configDir}/temp", - "**/*.spec.ts" - ] + "include": ["${configDir}/src"], + "exclude": ["${configDir}/dist", "${configDir}/build", "${configDir}/temp", "**/*.spec.ts"] } From cc4dafc615aad67b5e5bd5dd8a611c7e4f5b095d Mon Sep 17 00:00:00 2001 From: Sean Zubrickas Date: Fri, 19 Dec 2025 13:32:19 -0500 Subject: [PATCH 32/67] docs: fix duplicate anchor links (#14976) --- docs/fields/blocks.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/fields/blocks.mdx b/docs/fields/blocks.mdx index 5fb7062f380..a47fcb688ab 100644 --- a/docs/fields/blocks.mdx +++ b/docs/fields/blocks.mdx @@ -40,7 +40,7 @@ This page is divided into two parts: first, the settings of the Blocks Field, an ## Block Field -### Config Options +### Block Config Options | Option | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -65,7 +65,7 @@ This page is divided into two parts: first, the settings of the Blocks Field, an _\* An asterisk denotes that a property is required._ -### Admin Options +### Block Admin Options To customize the appearance and behavior of the Blocks Field in the [Admin Panel](../admin/overview), you can use the `admin` option: From 7199ef73f385252abc8c26445aa15b765e4245c7 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Fri, 19 Dec 2025 12:00:08 -0800 Subject: [PATCH 33/67] test: move mongodb to different port to avoid port conflicts (#14993) This moves the exposed mongodb docker image port from 27017 to 27018 in order to avoid conflict with locally installed mongodb applications running on port 27017. Previously, you would have to make sure you don't have mongodb running locally when using the docker image - otherwise, it would fail to connect. It also adds the old .env variables commented out in the .env.example for users who do not wish to use docker. The CONTRIBUTING.md now includes docker installation steps for macOS users. --- .env.example | 13 +++++++++++++ .github/actions/start-database/action.yml | 4 ++-- CONTRIBUTING.md | 15 ++++++++++----- test/generateDatabaseAdapter.ts | 7 ++++--- test/helpers/db/mongodb-atlas/docker-compose.yml | 2 +- .../db/mongodb-atlas/run-test-connection.ts | 2 +- test/helpers/db/mongodb/docker-compose.yml | 2 +- test/helpers/db/mongodb/run-test-connection.ts | 2 +- 8 files changed, 33 insertions(+), 14 deletions(-) diff --git a/.env.example b/.env.example index 57137813bbd..fe0835ee7ce 100644 --- a/.env.example +++ b/.env.example @@ -3,3 +3,16 @@ PAYLOAD_DATABASE=mongodb # Optional - used for the `translateNewKeys` script OPENAI_KEY= + + + + + + + + + +# If you're NOT using our docker scripts and want to manually install your database, uncomment these and point them to your local database. +# Do not uncomment these if you're using our Docker scripts to run your database. +# MONGODB_URL=mongodb://127.0.0.1/payloadtests +# POSTGRES_URL=postgres://127.0.0.1:5432/payloadtests diff --git a/.github/actions/start-database/action.yml b/.github/actions/start-database/action.yml index 1698aab39b7..57143730c92 100644 --- a/.github/actions/start-database/action.yml +++ b/.github/actions/start-database/action.yml @@ -26,7 +26,7 @@ runs: shell: bash run: | docker compose -f test/helpers/db/mongodb/docker-compose.yml up -d --wait - echo "url=mongodb://payload:payload@localhost:27017/payload?authSource=admin&directConnection=true&replicaSet=rs0" >> $GITHUB_OUTPUT + echo "url=mongodb://payload:payload@localhost:27018/payload?authSource=admin&directConnection=true&replicaSet=rs0" >> $GITHUB_OUTPUT - name: Start MongoDB Atlas Local id: mongodb-atlas @@ -34,7 +34,7 @@ runs: shell: bash run: | docker compose -f test/helpers/db/mongodb-atlas/docker-compose.yml up -d --wait - echo "url=mongodb://localhost:27018/payload?directConnection=true&replicaSet=mongodb-atlas-local" >> $GITHUB_OUTPUT + echo "url=mongodb://localhost:27019/payload?directConnection=true&replicaSet=mongodb-atlas-local" >> $GITHUB_OUTPUT - name: Start PostgreSQL id: postgres diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c25ba0cbc88..89202de8ad5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,7 +87,9 @@ Set `PAYLOAD_DATABASE` in your `.env` file to choose the database adapter: - `supabase` - Supabase (PostgreSQL) - `d1` - D1 (SQLite) -Then use Docker to start your database: +Then use Docker to start your database. + +On MacOS, the easiest way to install Docker is to use brew. Simply run `pnpm install --cask docker`, open the docker desktop app, apply the recommended settings and you're good to go. ### PostgreSQL @@ -107,7 +109,7 @@ pnpm docker:mongodb:restart:clean # Start fresh (removes data) pnpm docker:mongodb:stop # Stop ``` -URL: `mongodb://payload:payload@localhost:27017/payload?authSource=admin&directConnection=true&replicaSet=rs0` +URL: `mongodb://payload:payload@localhost:27018/payload?authSource=admin&directConnection=true&replicaSet=rs0` ### MongoDB Atlas Local @@ -117,7 +119,7 @@ pnpm docker:mongodb-atlas:restart:clean # Start fresh (removes data) pnpm docker:mongodb-atlas:stop # Stop ``` -URL: `mongodb://localhost:27018/payload?directConnection=true&replicaSet=mongodb-atlas-local` (no auth required) +URL: `mongodb://localhost:27019/payload?directConnection=true&replicaSet=mongodb-atlas-local` (no auth required) ### SQLite @@ -125,9 +127,12 @@ SQLite databases don't require Docker - they're stored as files in the project. ### Testing with your own database -If you wish to use your own MongoDB database for the `test` directory instead of using the docker database, all you need to do is add the following env variable to your `.env` file: +If you wish to use your own MongoDB database for the `test` directory instead of using the docker database, add the following to your `.env` file: -- `DATABASE_URL` to your database URL e.g. `mongodb://127.0.0.1/your-test-db`. +```env +MONGODB_URL=mongodb://127.0.0.1/payloadtests # Point this to your locally installed MongoDB database +POSTGRES_URL=postgres://127.0.0.1:5432/payloadtests # Point this to your locally installed PostgreSQL database +``` ### Running the e2e and int tests diff --git a/test/generateDatabaseAdapter.ts b/test/generateDatabaseAdapter.ts index 985251b9090..cffadbb63af 100644 --- a/test/generateDatabaseAdapter.ts +++ b/test/generateDatabaseAdapter.ts @@ -5,11 +5,12 @@ import { fileURLToPath } from 'node:url' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) +// Runs on port 27018 to avoid conflicts with locally installed MongoDB const mongooseAdapterArgs = ` ensureIndexes: true, url: process.env.MONGODB_URL || process.env.DATABASE_URL || - 'mongodb://payload:payload@localhost:27017/payload?authSource=admin&directConnection=true&replicaSet=rs0', + 'mongodb://payload:payload@localhost:27018/payload?authSource=admin&directConnection=true&replicaSet=rs0', ` export const allDatabaseAdapters = { @@ -21,7 +22,7 @@ export const allDatabaseAdapters = { })`, // mongodb-atlas uses Docker-based MongoDB Atlas Local (all-in-one with search) // Start with: pnpm docker:mongodb-atlas:start - // Runs on port 27018 to avoid conflicts with mongodb + // Runs on port 27019 to avoid conflicts with mongodb 'mongodb-atlas': ` import { mongooseAdapter } from '@payloadcms/db-mongodb' @@ -29,7 +30,7 @@ export const allDatabaseAdapters = { ensureIndexes: true, url: process.env.MONGODB_ATLAS_URL || process.env.DATABASE_URL || - 'mongodb://localhost:27018/payload?directConnection=true&replicaSet=mongodb-atlas-local', + 'mongodb://localhost:27019/payload?directConnection=true&replicaSet=mongodb-atlas-local', })`, cosmosdb: ` import { mongooseAdapter, compatibilityOptions } from '@payloadcms/db-mongodb' diff --git a/test/helpers/db/mongodb-atlas/docker-compose.yml b/test/helpers/db/mongodb-atlas/docker-compose.yml index 61d56266c78..8996cd59f6e 100644 --- a/test/helpers/db/mongodb-atlas/docker-compose.yml +++ b/test/helpers/db/mongodb-atlas/docker-compose.yml @@ -16,7 +16,7 @@ services: container_name: mongodb-atlas-payload-test hostname: mongodb-atlas-local # Sets a fixed replica set name (used in connection string replicaSet param) ports: - - '27018:27017' + - '27019:27017' volumes: - mongodb_atlas_data:/data/db environment: diff --git a/test/helpers/db/mongodb-atlas/run-test-connection.ts b/test/helpers/db/mongodb-atlas/run-test-connection.ts index b2a1422926c..f152b3ed3c8 100644 --- a/test/helpers/db/mongodb-atlas/run-test-connection.ts +++ b/test/helpers/db/mongodb-atlas/run-test-connection.ts @@ -9,5 +9,5 @@ import { testConnection } from '../mongodb/test-connection.js' await testConnection( process.env.MONGODB_ATLAS_URL || - 'mongodb://localhost:27018/payload?directConnection=true&replicaSet=mongodb-atlas-local', + 'mongodb://localhost:27019/payload?directConnection=true&replicaSet=mongodb-atlas-local', ) diff --git a/test/helpers/db/mongodb/docker-compose.yml b/test/helpers/db/mongodb/docker-compose.yml index eb6c94189a9..be447e6f21a 100644 --- a/test/helpers/db/mongodb/docker-compose.yml +++ b/test/helpers/db/mongodb/docker-compose.yml @@ -17,7 +17,7 @@ services: image: mongodb/mongodb-community-server:8.2-ubi9 container_name: mongodb-payload-test ports: - - '27017:27017' + - '27018:27017' volumes: - mongodb_data:/data/db - ./keyfile:/etc/mongodb/keyfile:ro diff --git a/test/helpers/db/mongodb/run-test-connection.ts b/test/helpers/db/mongodb/run-test-connection.ts index e4deb5811e4..571456a82f7 100644 --- a/test/helpers/db/mongodb/run-test-connection.ts +++ b/test/helpers/db/mongodb/run-test-connection.ts @@ -9,5 +9,5 @@ import { testConnection } from './test-connection.js' await testConnection( process.env.MONGODB_URL || - 'mongodb://payload:payload@localhost:27017/payload?authSource=admin&directConnection=true&replicaSet=rs0', + 'mongodb://payload:payload@localhost:27018/payload?authSource=admin&directConnection=true&replicaSet=rs0', ) From 4e220d26f1f012300c544be5d7b9de7decf62a15 Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Fri, 19 Dec 2025 23:07:14 +0200 Subject: [PATCH 34/67] test: migrate to `vitest` (#14337) Continuation of https://github.com/payloadcms/payload/pull/10200 * For VSCode - you'll need to install the official plugin https://marketplace.visualstudio.com/items?itemName=vitest.explorer * Every test suite now explicitly imports the test runner functions like `describe`, `expect`, instead of using it from `global`. While `vitest` supports globals with https://vitest.dev/config/#globals, the main benefit of not doing this is that we don't conflict with test runners that have the same functions, e.g `playwright` and `tstyche`. * Now we have only 1 test config file that uses [projects](https://vitest.dev/guide/projects) for unit and integration tests --------- Co-authored-by: Alessio Gravili --- .github/reproduction-guide.md | 6 +- .vscode/extensions.json | 6 +- .vscode/settings.json | 23 +- CLAUDE.md | 2 +- CONTRIBUTING.md | 2 +- ISSUE_GUIDE.md | 4 +- eslint.config.js | 4 +- jest.config.js | 58 - package.json | 16 +- packages/create-payload-app/jest.config.js | 32 - packages/create-payload-app/package.json | 1 - .../src/ast-integration.spec.ts | 1 + .../src/lib/ast/package-json.spec.ts | 1 + .../src/lib/ast/payload-config.spec.ts | 1 + .../src/lib/ast/utils.spec.ts | 1 + .../src/lib/create-project.spec.ts | 7 +- .../src/lib/manage-env-files.spec.ts | 4 +- .../src/lib/wrap-next-config.spec.ts | 4 +- .../src/queries/buildSortParam.spec.ts | 1 + .../queries/getLocalizedSortProperty.spec.ts | 2 +- .../src/utilities/transform.spec.ts | 2 +- .../src/utilities/isValidStringID.spec.ts | 1 + packages/email-nodemailer/src/plugin.spec.ts | 6 +- packages/email-resend/jest.config.js | 17 - packages/email-resend/package.json | 4 +- .../email-resend/src/email-resend.spec.ts | 21 +- packages/eslint-config/configs/jest/index.mjs | 15 +- .../graphql/src/utilities/formatName.spec.ts | 1 + .../utilities/countChangedFields.spec.ts | 4 +- .../utilities/fieldHasChanges.spec.ts | 2 + .../getFieldsForRowComparison.spec.ts | 4 +- packages/payload-cloud/jest.config.js | 32 - packages/payload-cloud/package.json | 1 - packages/payload-cloud/src/email.spec.ts | 9 +- packages/payload-cloud/src/plugin.spec.ts | 16 +- packages/payload-cloud/vitest.config.ts | 7 + packages/payload/src/auth/cookies.spec.ts | 1 + .../generateImportMap.spec.ts | 3 +- .../src/collections/config/useAsTitle.spec.ts | 1 + .../migrations/findMigrationDir.spec.ts | 3 +- .../database/migrations/readMigrationFiles.ts | 7 +- .../fields/config/reservedFieldNames.spec.ts | 1 + .../src/fields/config/sanitize.spec.ts | 1 + .../payload/src/fields/validations.spec.ts | 5 +- .../runJobs/runJob/importHandlerPath.ts | 9 +- .../src/uploads/mimeTypeValidator.spec.ts | 1 + .../addSelectGenericsToGeneratedTypes.spec.ts | 5 +- .../utilities/combineWhereConstraints.spec.ts | 1 + .../src/utilities/configToJSONSchema.spec.ts | 1 + .../utilities/flattenTopLevelFields.spec.ts | 1 + .../src/utilities/formatAdminURL.spec.ts | 1 + .../src/utilities/formatLabels.spec.ts | 1 + .../src/utilities/getFieldByPath.spec.ts | 1 + .../src/utilities/getFieldPermissions.spec.ts | 1 + .../src/utilities/getSafeRedirect.spec.ts | 1 + .../src/utilities/parseParams/index.spec.ts | 1 + .../src/utilities/sanitizePermissions.spec.ts | 2 +- .../sanitizeUserDataForEmail.spec.ts | 1 + .../src/utilities/accessComposition.spec.ts | 1 + .../defaultProductsValidation.spec.ts | 1 + .../utilities/getCollectionSlugMap.spec.ts | 15 +- .../utilities/sanitizePluginConfig.spec.ts | 19 +- packages/plugin-sentry/jest.config.js | 32 - packages/plugin-sentry/src/plugin.spec.ts | 7 +- .../src/dependencyChecker.spec.ts | 2 +- .../convertLexicalToPlaintext.spec.ts | 1 + .../src/lexical/utils/url.spec.ts | 2 +- .../src/utilities/jsx/jsx.spec.ts | 1 + .../fieldSchemasToFormState.spec.js | 14 +- .../normalizeRelationshipValue.spec.ts | 3 +- pnpm-lock.yaml | 1157 +++++++++++------ test/_community/int.spec.ts | 1 + test/access-control/int.spec.ts | 3 +- test/access-control/postgres-logs.int.spec.ts | 12 +- test/admin-root/int.spec.ts | 1 + test/array-update/int.spec.ts | 1 + test/auth/custom-strategy/int.spec.ts | 1 + .../forgot-password-localized/int.spec.ts | 1 + test/auth/int.spec.ts | 6 +- test/auth/removed-token/int.spec.ts | 1 + test/collections-graphql/int.spec.ts | 1 + test/collections-rest/int.spec.ts | 1 + test/config/int.spec.ts | 1 + test/create-payload-app/int.spec.ts | 6 +- test/custom-graphql/int.spec.ts | 1 + test/database/int.spec.ts | 52 +- test/database/postgres-logs.int.spec.ts | 12 +- .../int.spec.ts | 7 +- test/database/postgres-vector.int.spec.ts | 4 +- .../sqlite-bound-parameters-limit.int.spec.ts | 3 +- test/database/up-down-migration/int.spec.ts | 8 +- ...50811_134524.json => 20251030_115916.json} | 10 +- ...{20250811_134524.ts => 20251030_115916.ts} | 6 +- .../up-down-migration/migrations/index.ts | 8 +- test/dataloader/int.spec.ts | 3 +- test/endpoints/int.spec.ts | 1 + test/fields-relationship/int.spec.ts | 1 + test/fields/int.spec.ts | 3 +- test/folders-browse-by-disabled/int.spec.ts | 4 +- test/folders/int.spec.ts | 2 + test/form-state/int.spec.ts | 1 + test/globals/int.spec.ts | 1 + test/graphql/int.spec.ts | 1 + test/helpers.ts | 19 - test/helpers/isMongoose.ts | 2 +- test/hooks/int.spec.ts | 1 + test/jest.config.js | 22 - test/joins/int.spec.ts | 1 + test/kv/int.spec.ts | 1 + test/lexical-mdx/int.spec.ts | 13 +- test/lexical/lexical.int.spec.ts | 2 +- test/live-preview/int.spec.ts | 3 +- test/loader/int.spec.ts | 2 + test/localization/int.spec.ts | 2 +- test/locked-documents/int.spec.ts | 1 + test/login-with-username/int.spec.ts | 1 + test/package.json | 12 +- test/payload-cloud/int.spec.ts | 1 + test/plugin-cloud-storage/int.spec.ts | 23 +- test/plugin-ecommerce/int.spec.ts | 1 + test/plugin-form-builder/int.spec.ts | 1 + test/plugin-import-export/int.spec.ts | 1 + test/plugin-mcp/int.spec.ts | 1 + test/plugin-multi-tenant/int.spec.ts | 1 + test/plugin-nested-docs/int.spec.ts | 1 + test/plugin-redirects/int.spec.ts | 1 + test/plugin-search/int.spec.ts | 1 + test/plugin-sentry/int.spec.ts | 1 + test/plugin-seo/int.spec.ts | 1 + test/plugin-stripe/int.spec.ts | 1 + test/plugins/int.spec.ts | 1 + test/query-presets/int.spec.ts | 1 + test/queues/cli.int.spec.ts | 1 + test/queues/int.spec.ts | 2 +- test/queues/postgres-logs.int.spec.ts | 4 +- test/queues/schedules-autocron.int.spec.ts | 1 + test/queues/schedules.int.spec.ts | 1 + test/relationships/int.spec.ts | 3 +- test/sdk/int.spec.ts | 2 +- test/select/int.spec.ts | 14 +- test/select/postgreslogs.int.spec.ts | 6 +- test/sort/int.spec.ts | 1 + test/storage-azure/int.spec.ts | 3 +- test/storage-s3/int.spec.ts | 1 + test/trash/int.spec.ts | 1 + test/tsconfig.json | 2 +- test/uploads/int.spec.ts | 9 +- test/versions/int.spec.ts | 1 + test/{jest.setup.js => vitest.setup.ts} | 25 +- tsconfig.base.json | 2 +- tsconfig.json | 2 +- vitest.config.ts | 32 + 152 files changed, 1094 insertions(+), 924 deletions(-) delete mode 100644 jest.config.js delete mode 100644 packages/create-payload-app/jest.config.js delete mode 100644 packages/email-resend/jest.config.js delete mode 100644 packages/payload-cloud/jest.config.js create mode 100644 packages/payload-cloud/vitest.config.ts delete mode 100644 packages/plugin-sentry/jest.config.js rename test/database/up-down-migration/migrations/{20250811_134524.json => 20251030_115916.json} (98%) rename test/database/up-down-migration/migrations/{20250811_134524.ts => 20251030_115916.ts} (93%) delete mode 100644 test/jest.config.js rename test/{jest.setup.js => vitest.setup.ts} (63%) create mode 100644 vitest.config.ts diff --git a/.github/reproduction-guide.md b/.github/reproduction-guide.md index 50900fd4fdf..79cb91b3c49 100644 --- a/.github/reproduction-guide.md +++ b/.github/reproduction-guide.md @@ -20,7 +20,7 @@ ``` - `config.ts` - This is the _granular_ Payload config for testing. It should be as lightweight as possible. Reference existing configs for an example -- `int.spec.ts` [Optional] - This is the test file run by jest. Any test file must have a `*int.spec.ts` suffix. +- `int.spec.ts` [Optional] - This is the test file run by vitest. Any test file must have a `*int.spec.ts` suffix. - `e2e.spec.ts` [Optional] - This is the end-to-end test file that will load up the admin UI using the above config and run Playwright tests. - `payload-types.ts` - Generated types from `config.ts`. Generate this file by running `pnpm dev:generate-types _community`. @@ -34,11 +34,11 @@ An issue does not need to have failing tests — reproduction steps with your fo ### Running integration tests (Payload API tests) -First install [Jest Runner for VSVode](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner). +First install [Vitest Plugin for VSCode](https://marketplace.visualstudio.com/items?itemName=vitest.explorer). There are a couple ways run integration tests: -- **Granularly** - you can run individual tests in vscode by installing the Jest Runner plugin and using that to run individual tests. Clicking the `debug` button will run the test in debug mode allowing you to set break points. +- **Granularly** - you can run individual tests in vscode by installing the [Vitest Plugin](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) and using that to run individual tests. Clicking the `debug` button will run the test in debug mode allowing you to set break points. diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0580659a295..a46d5032898 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,8 +1,8 @@ { "recommendations": [ - "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", - "ms-playwright.playwright", - "orta.vscode-jest" + "dbaeumer.vscode-eslint", + "vitest.explorer", + "ms-playwright.playwright" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 76de0a81ded..28630977843 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,30 +17,9 @@ "typescript.tsdk": "node_modules/typescript/lib", // Load .git-blame-ignore-revs file "gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"], - "jestrunner.jestCommand": "pnpm exec cross-env NODE_OPTIONS=\"--no-deprecation\" node 'node_modules/jest/bin/jest.js'", - "jestrunner.changeDirectoryToWorkspaceRoot": false, - "jestrunner.debugOptions": { - "runtimeArgs": ["--no-deprecation"] - }, // Essentially disables bun test buttons "bun.test.filePattern": "bun.test.ts", "playwright.env": { "NODE_OPTIONS": "--no-deprecation --no-experimental-strip-types" - }, - "jest.virtualFolders": [ - { - "name": "root", - "rootPath": ".", - "runMode": { - "type": "on-demand" - } - }, - { - "name": "test", - "rootPath": "test", - "runMode": { - "type": "on-demand" - } - } - ] + } } diff --git a/CLAUDE.md b/CLAUDE.md index 22cd289ee5f..1204681c697 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -96,7 +96,7 @@ Each test directory in `test/` follows this pattern: ``` test// ├── config.ts # Lightweight Payload config for testing -├── int.spec.ts # Integration tests (Jest) +├── int.spec.ts # Integration tests (Vitest) ├── e2e.spec.ts # End-to-end tests (Playwright) └── payload-types.ts # Generated types ``` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 89202de8ad5..a856bb836ea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -55,7 +55,7 @@ A typical directory with `test/` will be structured like this: ``` - `config.ts` - This is the _granular_ Payload config for testing. It should be as lightweight as possible. Reference existing configs for an example -- `int.spec.ts` - This is the test file run by jest. Any test file must have a `*int.spec.ts` suffix. +- `int.spec.ts` - This is the test file run by vitest. Any test file must have a `*int.spec.ts` suffix. - `e2e.spec.ts` - This is the end-to-end test file that will load up the admin UI using the above config and run Playwright tests. These tests are typically only needed if a large change is being made to the Admin UI. - `payload-types.ts` - Generated types from `config.ts`. Generate this file by running `pnpm dev:generate-types my-test-dir`. Replace `my-test-dir` with the name of your testing directory. diff --git a/ISSUE_GUIDE.md b/ISSUE_GUIDE.md index 455882bdb21..d7e9fbc321d 100644 --- a/ISSUE_GUIDE.md +++ b/ISSUE_GUIDE.md @@ -19,7 +19,7 @@ To report an issue, please follow the steps below: ``` - `config.ts` - This is the _granular_ Payload config for testing. It should be as lightweight as possible. Reference existing configs for an example -- `int.spec.ts` [Optional] - This is the test file run by jest. Any test file must have a `*int.spec.ts` suffix. +- `int.spec.ts` [Optional] - This is the test file run by vitest. Any test file must have a `*int.spec.ts` suffix. - `e2e.spec.ts` [Optional] - This is the end-to-end test file that will load up the admin UI using the above config and run Playwright tests. - `payload-types.ts` - Generated types from `config.ts`. Generate this file by running `pnpm dev:generate-types _community`. @@ -43,7 +43,7 @@ An issue does not need to have failing tests — reproduction steps with your fo There are a couple ways to do this: -- **Granularly** - you can run individual tests in vscode by installing the Jest Runner plugin and using that to run individual tests. Clicking the `debug` button will run the test in debug mode allowing you to set break points. +- **Granularly** - you can run individual tests in vscode by installing the [Vitest Plugin](https://marketplace.visualstudio.com/items?itemName=vitest.explorer) and using that to run individual tests. Clicking the `debug` button will run the test in debug mode allowing you to set break points. diff --git a/eslint.config.js b/eslint.config.js index b1cf9054aee..3721c090b11 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -9,7 +9,8 @@ export const defaultESLintIgnores = [ '**/.pnp.*', '**/.svn', '**/playwright.config.ts', - '**/jest.config.js', + '**/vitest.config.ts', + '**/vitest.setup.ts', '**/tsconfig.tsbuildinfo', '**/README.md', '**/eslint.config.js', @@ -23,7 +24,6 @@ export const defaultESLintIgnores = [ 'next-env.d.ts', '**/app', 'src/**/*.spec.ts', - '**/jest.setup.js', 'packages/payload/rollup.dts.config.mjs', ] diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index defee6f0147..00000000000 --- a/jest.config.js +++ /dev/null @@ -1,58 +0,0 @@ -const esModules = [ - // file-type and all dependencies: https://github.com/sindresorhus/file-type - 'file-type', - 'strtok3', - 'readable-web-to-node-stream', - 'token-types', - 'peek-readable', - 'locate-path', - 'p-locate', - 'p-limit', - 'yocto-queue', - 'unicorn-magic', - 'path-exists', - 'qs-esm', - 'uint8array-extras', - '@faceless-ui/window-info', - '@faceless-ui/modal', - '@faceless-ui/scroll-info', -].join('|') - -import path from 'path' -import { fileURLToPath } from 'url' - -const filename = fileURLToPath(import.meta.url) -const dirname = path.dirname(filename) - -/** @type {import('jest').Config} */ -const baseJestConfig = { - extensionsToTreatAsEsm: ['.ts', '.tsx'], - setupFilesAfterEnv: ['/test/jest.setup.js'], - transformIgnorePatterns: [ - `/node_modules/(?!.pnpm)(?!(${esModules})/)`, - `/node_modules/.pnpm/(?!(${esModules.replace(/\//g, '\\+')})@)`, - ], - moduleNameMapper: { - '\\.(css|scss)$': '/test/helpers/mocks/emptyModule.js', - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': - '/test/helpers/mocks/fileMock.js', - '^(\\.{1,2}/.*)\\.js$': '$1', - }, - testEnvironment: 'node', - testMatch: ['/packages/*/src/**/*.spec.ts'], - testTimeout: 90000, - transform: { - '^.+\\.(t|j)sx?$': ['@swc/jest'], - }, - verbose: true, - reporters: [ - path.resolve(dirname, './test/jest-spec-reporter.cjs'), - path.resolve(dirname, './test/jestreporter.cjs'), - ], -} - -if (process.env.CI) { - baseJestConfig.reporters.push(['github-actions', { silent: false }], 'summary') -} - -export default baseJestConfig diff --git a/package.json b/package.json index f139045eb0a..438ad3c4fe4 100644 --- a/package.json +++ b/package.json @@ -131,12 +131,12 @@ "test:e2e:prod": "pnpm prepare-run-test-against-prod && pnpm runts ./test/runE2E.ts --prod", "test:e2e:prod:ci": "pnpm prepare-run-test-against-prod:ci && pnpm runts ./test/runE2E.ts --prod", "test:e2e:prod:ci:noturbo": "pnpm prepare-run-test-against-prod:ci && pnpm runts ./test/runE2E.ts --prod --no-turbo", - "test:int": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 DISABLE_LOGGING=true jest --forceExit --detectOpenHandles --config=test/jest.config.js --runInBand", - "test:int:firestore": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 PAYLOAD_DATABASE=firestore DISABLE_LOGGING=true jest --forceExit --detectOpenHandles --config=test/jest.config.js --runInBand", - "test:int:postgres": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 PAYLOAD_DATABASE=postgres DISABLE_LOGGING=true jest --forceExit --detectOpenHandles --config=test/jest.config.js --runInBand", - "test:int:sqlite": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 PAYLOAD_DATABASE=sqlite DISABLE_LOGGING=true jest --forceExit --detectOpenHandles --config=test/jest.config.js --runInBand", + "test:int": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 DISABLE_LOGGING=true vitest --project int", + "test:int:firestore": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 PAYLOAD_DATABASE=firestore DISABLE_LOGGING=true vitest --project int", + "test:int:postgres": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 PAYLOAD_DATABASE=postgres DISABLE_LOGGING=true vitest --project int", + "test:int:sqlite": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 PAYLOAD_DATABASE=sqlite DISABLE_LOGGING=true vitest --project int", "test:types": "tstyche", - "test:unit": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 DISABLE_LOGGING=true jest --forceExit --detectOpenHandles --config=jest.config.js --runInBand", + "test:unit": "vitest run --project unit", "translateNewKeys": "pnpm --filter @tools/scripts run generateTranslations:core" }, "lint-staged": { @@ -152,7 +152,6 @@ }, "devDependencies": { "@axe-core/playwright": "4.11.0", - "@jest/globals": "29.7.0", "@libsql/client": "0.14.0", "@next/bundle-analyzer": "15.4.7", "@payloadcms/db-postgres": "workspace:*", @@ -167,7 +166,6 @@ "@swc/core": "1.15.3", "@swc/jest": "0.2.39", "@types/fs-extra": "^11.0.2", - "@types/jest": "29.5.12", "@types/minimist": "1.2.5", "@types/node": "22.15.30", "@types/react": "19.2.1", @@ -188,7 +186,6 @@ "fs-extra": "10.1.0", "globby": "11.1.0", "husky": "9.0.11", - "jest": "29.7.0", "lint-staged": "15.2.7", "minimist": "1.2.8", "mongoose": "8.15.1", @@ -212,6 +209,7 @@ "tsx": "4.19.2", "turbo": "^2.5.4", "typescript": "5.7.3", + "vitest": "4.0.15", "wrangler": "~4.42.0" }, "packageManager": "pnpm@9.7.1", @@ -224,7 +222,7 @@ "copyfiles": "$copyfiles", "cross-env": "$cross-env", "dotenv": "$dotenv", - "graphql": "^16.8.1", + "graphql": "16.8.1", "react": "$react", "react-dom": "$react-dom", "typescript": "$typescript" diff --git a/packages/create-payload-app/jest.config.js b/packages/create-payload-app/jest.config.js deleted file mode 100644 index b6bd5c7bd38..00000000000 --- a/packages/create-payload-app/jest.config.js +++ /dev/null @@ -1,32 +0,0 @@ -// import baseConfig from '../../jest.config.js' - -// /** @type {import('@jest/types').Config} */ -// const customJestConfig = { -// ...baseConfig, -// setupFilesAfterEnv: null, -// testMatch: ['**/src/**/?(*.)+(spec|test|it-test).[tj]s?(x)'], -// testTimeout: 20000, -// } - -// export default customJestConfig - -/** @type {import('jest').Config} */ -const customJestConfig = { - extensionsToTreatAsEsm: ['.ts', '.tsx'], - // setupFilesAfterEnv: ['/jest.setup.js'], - moduleNameMapper: { - '\\.(css|scss)$': '/helpers/mocks/emptyModule.js', - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': - '/test/helpers/mocks/fileMock.js', - '^(\\.{1,2}/.*)\\.js$': '$1', - }, - testEnvironment: 'node', - testMatch: ['/**/*spec.ts'], - testTimeout: 160000, - transform: { - '^.+\\.(t|j)sx?$': ['@swc/jest'], - }, - verbose: true, -} - -export default customJestConfig diff --git a/packages/create-payload-app/package.json b/packages/create-payload-app/package.json index c15d31f048e..e8c3c4752a3 100644 --- a/packages/create-payload-app/package.json +++ b/packages/create-payload-app/package.json @@ -78,7 +78,6 @@ "devDependencies": { "@types/esprima": "^4.0.6", "@types/fs-extra": "^9.0.12", - "@types/jest": "29.5.12", "@types/node": "22.15.30" }, "engines": { diff --git a/packages/create-payload-app/src/ast-integration.spec.ts b/packages/create-payload-app/src/ast-integration.spec.ts index 0297d898b5d..53b53cd29c9 100644 --- a/packages/create-payload-app/src/ast-integration.spec.ts +++ b/packages/create-payload-app/src/ast-integration.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest' import * as fs from 'fs' import * as fse from 'fs-extra' import * as path from 'path' diff --git a/packages/create-payload-app/src/lib/ast/package-json.spec.ts b/packages/create-payload-app/src/lib/ast/package-json.spec.ts index d2e60a9de0b..08770ce2c43 100644 --- a/packages/create-payload-app/src/lib/ast/package-json.spec.ts +++ b/packages/create-payload-app/src/lib/ast/package-json.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest' import { updatePackageJson } from './package-json' import * as fs from 'fs' import * as path from 'path' diff --git a/packages/create-payload-app/src/lib/ast/payload-config.spec.ts b/packages/create-payload-app/src/lib/ast/payload-config.spec.ts index 7c443cfcf7a..e0011f89880 100644 --- a/packages/create-payload-app/src/lib/ast/payload-config.spec.ts +++ b/packages/create-payload-app/src/lib/ast/payload-config.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest' import { Project } from 'ts-morph' import { addDatabaseAdapter, diff --git a/packages/create-payload-app/src/lib/ast/utils.spec.ts b/packages/create-payload-app/src/lib/ast/utils.spec.ts index 1c3510dfaf6..34402918302 100644 --- a/packages/create-payload-app/src/lib/ast/utils.spec.ts +++ b/packages/create-payload-app/src/lib/ast/utils.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { Project } from 'ts-morph' import { addImportDeclaration, diff --git a/packages/create-payload-app/src/lib/create-project.spec.ts b/packages/create-payload-app/src/lib/create-project.spec.ts index 7ce761a5ef3..a0dc3e02133 100644 --- a/packages/create-payload-app/src/lib/create-project.spec.ts +++ b/packages/create-payload-app/src/lib/create-project.spec.ts @@ -1,10 +1,9 @@ -import { jest } from '@jest/globals' import fs from 'fs' import fse from 'fs-extra' import globby from 'globby' import * as os from 'node:os' import path from 'path' - +import { afterEach, beforeAll, beforeEach, describe, expect, it, vitest } from 'vitest' import type { CliArgs, DbType, ProjectExample, ProjectTemplate } from '../types.js' import { createProject, updatePackageJSONDependencies } from './create-project.js' @@ -15,7 +14,7 @@ describe('createProject', () => { beforeAll(() => { // eslint-disable-next-line no-console - console.log = jest.fn() + console.log = vitest.fn() }) beforeEach(() => { @@ -110,7 +109,7 @@ describe('createProject', () => { // Check package name and description expect(packageJson.name).toStrictEqual(projectName) - }) + }, 90_000) describe('creates project from template', () => { const templates = getValidTemplates() diff --git a/packages/create-payload-app/src/lib/manage-env-files.spec.ts b/packages/create-payload-app/src/lib/manage-env-files.spec.ts index 0257bea01e1..69abf6305be 100644 --- a/packages/create-payload-app/src/lib/manage-env-files.spec.ts +++ b/packages/create-payload-app/src/lib/manage-env-files.spec.ts @@ -1,8 +1,8 @@ -import { jest } from '@jest/globals' import fs from 'fs' import fse from 'fs-extra' import * as os from 'node:os' import path from 'path' +import { afterEach, beforeAll, beforeEach, describe, expect, it, vitest } from 'vitest' import type { CliArgs } from '../types.js' @@ -15,7 +15,7 @@ describe('createProject', () => { beforeAll(() => { // eslint-disable-next-line no-console - console.log = jest.fn() + console.log = vitest.fn() }) beforeEach(() => { diff --git a/packages/create-payload-app/src/lib/wrap-next-config.spec.ts b/packages/create-payload-app/src/lib/wrap-next-config.spec.ts index fa9e978928d..ba4215e7ff0 100644 --- a/packages/create-payload-app/src/lib/wrap-next-config.spec.ts +++ b/packages/create-payload-app/src/lib/wrap-next-config.spec.ts @@ -1,5 +1,5 @@ import * as p from '@clack/prompts' -import { jest } from '@jest/globals' +import { describe, it, expect, vitest } from 'vitest' import { parseAndModifyConfigContent, withPayloadStatement } from './wrap-next-config.js' @@ -159,7 +159,7 @@ describe('parseAndInsertWithPayload', () => { // Unsupported: export { wrapped as default } it('should give warning with a named export as default', async () => { - const warnLogSpy = jest.spyOn(p.log, 'warn').mockImplementation(() => {}) + const warnLogSpy = vitest.spyOn(p.log, 'warn').mockImplementation(() => {}) const { modifiedConfigContent, success } = await parseAndModifyConfigContent( esmConfigs.nextConfigExportNamedDefault, diff --git a/packages/db-mongodb/src/queries/buildSortParam.spec.ts b/packages/db-mongodb/src/queries/buildSortParam.spec.ts index 7e411f722bd..fa85fd9c434 100644 --- a/packages/db-mongodb/src/queries/buildSortParam.spec.ts +++ b/packages/db-mongodb/src/queries/buildSortParam.spec.ts @@ -1,4 +1,5 @@ import type { Config, SanitizedConfig } from 'payload' +import { describe, beforeAll, it, expect } from 'vitest' import { sanitizeConfig } from 'payload' diff --git a/packages/db-mongodb/src/queries/getLocalizedSortProperty.spec.ts b/packages/db-mongodb/src/queries/getLocalizedSortProperty.spec.ts index 618eb09f32d..dc84a5aa70d 100644 --- a/packages/db-mongodb/src/queries/getLocalizedSortProperty.spec.ts +++ b/packages/db-mongodb/src/queries/getLocalizedSortProperty.spec.ts @@ -1,5 +1,5 @@ +import { describe, beforeAll, it, expect } from 'vitest' import type { Config, SanitizedConfig } from 'payload' - import { flattenAllFields, sanitizeConfig } from 'payload' import { getLocalizedSortProperty } from './getLocalizedSortProperty.js' diff --git a/packages/db-mongodb/src/utilities/transform.spec.ts b/packages/db-mongodb/src/utilities/transform.spec.ts index 4796473e392..1de5b16e76b 100644 --- a/packages/db-mongodb/src/utilities/transform.spec.ts +++ b/packages/db-mongodb/src/utilities/transform.spec.ts @@ -1,5 +1,5 @@ +import { describe, it, expect } from 'vitest' import { flattenAllFields, type Field, type SanitizedConfig } from 'payload' - import { Types } from 'mongoose' import { transform } from './transform.js' diff --git a/packages/drizzle/src/utilities/isValidStringID.spec.ts b/packages/drizzle/src/utilities/isValidStringID.spec.ts index 32e0660f633..f89558d8b89 100644 --- a/packages/drizzle/src/utilities/isValidStringID.spec.ts +++ b/packages/drizzle/src/utilities/isValidStringID.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { isValidStringID } from './isValidStringID.js' describe('isValidStringID', () => { diff --git a/packages/email-nodemailer/src/plugin.spec.ts b/packages/email-nodemailer/src/plugin.spec.ts index 4c168ccd934..f2d6f5b12eb 100644 --- a/packages/email-nodemailer/src/plugin.spec.ts +++ b/packages/email-nodemailer/src/plugin.spec.ts @@ -1,6 +1,6 @@ import type { Transporter } from 'nodemailer' +import { describe, beforeEach, it, expect, Mock, vitest } from 'vitest' -import { jest } from '@jest/globals' import nodemailer from 'nodemailer' import type { NodemailerAdapterArgs } from './index.js' @@ -14,11 +14,11 @@ const defaultArgs: NodemailerAdapterArgs = { describe('email-nodemailer', () => { describe('transport verification', () => { - let mockedVerify: jest.Mock + let mockedVerify: Mock let mockTransport: Transporter beforeEach(() => { - mockedVerify = jest.fn() + mockedVerify = vitest.fn() mockTransport = nodemailer.createTransport({ name: 'existing-transport', // eslint-disable-next-line @typescript-eslint/require-await, @typescript-eslint/no-misused-promises diff --git a/packages/email-resend/jest.config.js b/packages/email-resend/jest.config.js deleted file mode 100644 index f2ca51eafeb..00000000000 --- a/packages/email-resend/jest.config.js +++ /dev/null @@ -1,17 +0,0 @@ -/** @type {import('jest').Config} */ -const customJestConfig = { - rootDir: '.', - extensionsToTreatAsEsm: ['.ts', '.tsx'], - moduleNameMapper: { - '^(\\.{1,2}/.*)\\.js$': '$1', - }, - testEnvironment: 'node', - testMatch: ['/**/*spec.ts'], - testTimeout: 10000, - transform: { - '^.+\\.(t|j)sx?$': ['@swc/jest'], - }, - verbose: true, -} - -export default customJestConfig diff --git a/packages/email-resend/package.json b/packages/email-resend/package.json index 44421ba53c6..cbd5c99fa60 100644 --- a/packages/email-resend/package.json +++ b/packages/email-resend/package.json @@ -39,11 +39,9 @@ "clean": "rimraf -g {dist,*.tsbuildinfo}", "lint": "eslint .", "lint:fix": "eslint . --fix", - "test": "jest" + "prepublishOnly": "pnpm clean && pnpm turbo build" }, "devDependencies": { - "@types/jest": "29.5.12", - "jest": "^29.7.0", "payload": "workspace:*" }, "peerDependencies": { diff --git a/packages/email-resend/src/email-resend.spec.ts b/packages/email-resend/src/email-resend.spec.ts index 531933e3dda..81639c53bd4 100644 --- a/packages/email-resend/src/email-resend.spec.ts +++ b/packages/email-resend/src/email-resend.spec.ts @@ -1,6 +1,5 @@ import type { Payload } from 'payload' - -import { jest } from '@jest/globals' +import { describe, afterEach, it, expect, vitest, Mock } from 'vitest' import { resendAdapter } from './index.js' @@ -16,19 +15,19 @@ describe('email-resend', () => { const mockPayload = {} as unknown as Payload afterEach(() => { - jest.clearAllMocks() + vitest.clearAllMocks() }) it('should handle sending an email', async () => { - global.fetch = jest.spyOn(global, 'fetch').mockImplementation( - jest.fn(() => + global.fetch = vitest.spyOn(global, 'fetch').mockImplementation( + vitest.fn(() => Promise.resolve({ json: () => { return { id: 'test-id' } }, }), - ) as jest.Mock, - ) as jest.Mock + ) as Mock, + ) as Mock const adapter = resendAdapter({ apiKey, @@ -62,13 +61,13 @@ describe('email-resend', () => { message: 'error information', statusCode: 403, } - global.fetch = jest.spyOn(global, 'fetch').mockImplementation( - jest.fn(() => + global.fetch = vitest.spyOn(global, 'fetch').mockImplementation( + vitest.fn(() => Promise.resolve({ json: () => errorResponse, }), - ) as jest.Mock, - ) as jest.Mock + ) as Mock, + ) as Mock const adapter = resendAdapter({ apiKey, diff --git a/packages/eslint-config/configs/jest/index.mjs b/packages/eslint-config/configs/jest/index.mjs index c695d477d78..88d9b7d3f05 100644 --- a/packages/eslint-config/configs/jest/index.mjs +++ b/packages/eslint-config/configs/jest/index.mjs @@ -5,19 +5,6 @@ import jest from 'eslint-plugin-jest' import { deepMerge } from '../../deepMerge.js' /** @type {import('eslint').Linter.Config} */ -export const index = deepMerge( - { - rules: jestRules, - }, - { - rules: jestDomRules, - }, - { - plugins: { - jest, - 'jest-dom': jestDom, - }, - }, -) +export const index = deepMerge({}) export default index diff --git a/packages/graphql/src/utilities/formatName.spec.ts b/packages/graphql/src/utilities/formatName.spec.ts index a450456495c..203b37d2d4c 100644 --- a/packages/graphql/src/utilities/formatName.spec.ts +++ b/packages/graphql/src/utilities/formatName.spec.ts @@ -1,4 +1,5 @@ /* eslint-disable jest/prefer-strict-equal */ +import { describe, it, expect } from 'vitest' import { formatName } from './formatName' describe('formatName', () => { diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/utilities/countChangedFields.spec.ts b/packages/next/src/views/Version/RenderFieldsToDiff/utilities/countChangedFields.spec.ts index fa32c364963..f3ed248ec75 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/utilities/countChangedFields.spec.ts +++ b/packages/next/src/views/Version/RenderFieldsToDiff/utilities/countChangedFields.spec.ts @@ -1,5 +1,7 @@ -import { countChangedFields, countChangedFieldsInRows } from './countChangedFields.js' import type { ClientField } from 'payload' +import { describe, it, expect } from 'vitest' + +import { countChangedFields, countChangedFieldsInRows } from './countChangedFields.js' describe('countChangedFields', () => { // locales can be undefined when not configured in payload.config.js diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/utilities/fieldHasChanges.spec.ts b/packages/next/src/views/Version/RenderFieldsToDiff/utilities/fieldHasChanges.spec.ts index 153fe1c5d70..72d85c1cb6c 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/utilities/fieldHasChanges.spec.ts +++ b/packages/next/src/views/Version/RenderFieldsToDiff/utilities/fieldHasChanges.spec.ts @@ -1,3 +1,5 @@ +import { describe, it, expect } from 'vitest' + import { fieldHasChanges } from './fieldHasChanges.js' describe('hasChanges', () => { diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/utilities/getFieldsForRowComparison.spec.ts b/packages/next/src/views/Version/RenderFieldsToDiff/utilities/getFieldsForRowComparison.spec.ts index db3d6f7c068..44a8216a102 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/utilities/getFieldsForRowComparison.spec.ts +++ b/packages/next/src/views/Version/RenderFieldsToDiff/utilities/getFieldsForRowComparison.spec.ts @@ -1,5 +1,7 @@ -import { getFieldsForRowComparison } from './getFieldsForRowComparison' import type { ArrayFieldClient, BlocksFieldClient, ClientField } from 'payload' +import { describe, it, expect } from 'vitest' + +import { getFieldsForRowComparison } from './getFieldsForRowComparison' describe('getFieldsForRowComparison', () => { describe('array fields', () => { diff --git a/packages/payload-cloud/jest.config.js b/packages/payload-cloud/jest.config.js deleted file mode 100644 index b0539a17900..00000000000 --- a/packages/payload-cloud/jest.config.js +++ /dev/null @@ -1,32 +0,0 @@ -import baseConfig from '../../jest.config.js' - -/** @type {import('jest').Config} */ -const customJestConfig = { - ...baseConfig, - setupFilesAfterEnv: null, - testMatch: ['**/src/**/?(*.)+(spec|test|it-test).[tj]s?(x)'], - testTimeout: 20000, - transform: { - '^.+\\.(t|j)sx?$': [ - '@swc/jest', - { - $schema: 'https://json.schemastore.org/swcrc', - sourceMaps: true, - exclude: ['/**/mocks'], - jsc: { - target: 'esnext', - parser: { - syntax: 'typescript', - tsx: true, - dts: true, - }, - }, - module: { - type: 'es6', - }, - }, - ], - }, -} - -export default customJestConfig diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index aab26b294fa..e82cb3ff77a 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -51,7 +51,6 @@ "nodemailer": "7.0.9" }, "devDependencies": { - "@types/jest": "29.5.12", "@types/nodemailer": "7.0.2", "payload": "workspace:*" }, diff --git a/packages/payload-cloud/src/email.spec.ts b/packages/payload-cloud/src/email.spec.ts index c104aa8ce7b..1b764f63ae3 100644 --- a/packages/payload-cloud/src/email.spec.ts +++ b/packages/payload-cloud/src/email.spec.ts @@ -1,6 +1,5 @@ import type { Config, Payload } from 'payload' - -import { jest } from '@jest/globals' +import { describe, beforeAll, beforeEach, it, expect, vitest } from 'vitest' import nodemailer from 'nodemailer' import { defaults } from 'payload' @@ -12,11 +11,11 @@ describe('email', () => { const defaultDomain = 'test.com' const apiKey = 'test' - const mockedPayload: Payload = jest.fn() as unknown as Payload + const mockedPayload: Payload = vitest.fn() as unknown as Payload beforeAll(() => { // Mock createTestAccount to prevent calling external services - jest.spyOn(nodemailer, 'createTestAccount').mockImplementation(() => { + vitest.spyOn(nodemailer, 'createTestAccount').mockImplementation(() => { return Promise.resolve({ imap: { host: 'imap.test.com', port: 993, secure: true }, pass: 'testpass', @@ -75,7 +74,7 @@ describe('email', () => { skipVerify, }) - const initializedEmail = email({ payload: mockedPayload }) + const initializedEmail = email!({ payload: mockedPayload }) expect(initializedEmail.defaultFromName).toStrictEqual(defaultFromName) expect(initializedEmail.defaultFromAddress).toStrictEqual(defaultFromAddress) diff --git a/packages/payload-cloud/src/plugin.spec.ts b/packages/payload-cloud/src/plugin.spec.ts index f69d90cb506..09f7f63dfc3 100644 --- a/packages/payload-cloud/src/plugin.spec.ts +++ b/packages/payload-cloud/src/plugin.spec.ts @@ -1,6 +1,6 @@ import type { Config, Payload } from 'payload' +import { describe, beforeAll, beforeEach, it, expect, test, vitest, Mock } from 'vitest' -import { jest } from '@jest/globals' import { nodemailerAdapter } from '@payloadcms/email-nodemailer' import nodemailer from 'nodemailer' import { defaults } from 'payload' @@ -13,20 +13,20 @@ import { defaults } from 'payload' // })) const mockedPayload: Payload = { - updateGlobal: jest.fn(), - findGlobal: jest.fn().mockReturnValue('instance'), + updateGlobal: vitest.fn(), + findGlobal: vitest.fn().mockReturnValue('instance'), } as unknown as Payload import { payloadCloudPlugin } from './plugin.js' describe('plugin', () => { - let createTransportSpy: jest.Spied + let createTransportSpy: Mock const skipVerify = true beforeAll(() => { // Mock createTestAccount to prevent calling external services - jest.spyOn(nodemailer, 'createTestAccount').mockImplementation(() => { + vitest.spyOn(nodemailer, 'createTestAccount').mockImplementation(() => { return Promise.resolve({ imap: { host: 'imap.test.com', port: 993, secure: true }, pass: 'testpass', @@ -39,12 +39,12 @@ describe('plugin', () => { }) beforeEach(() => { - createTransportSpy = jest.spyOn(nodemailer, 'createTransport').mockImplementationOnce(() => { + createTransportSpy = vitest.spyOn(nodemailer, 'createTransport').mockImplementationOnce(() => { return { transporter: { name: 'Nodemailer - SMTP', }, - verify: jest.fn(), + verify: vitest.fn(), } as unknown as ReturnType }) }) @@ -114,7 +114,7 @@ describe('plugin', () => { }) it('should not modify existing email transport', async () => { - const logSpy = jest.spyOn(console, 'log') + const logSpy = vitest.spyOn(console, 'log') const existingTransport = nodemailer.createTransport({ name: 'existing-transport', diff --git a/packages/payload-cloud/vitest.config.ts b/packages/payload-cloud/vitest.config.ts new file mode 100644 index 00000000000..16c70c33538 --- /dev/null +++ b/packages/payload-cloud/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineProject } from 'vitest/config' + +export default defineProject({ + test: { + testTimeout: 20000, + }, +}) diff --git a/packages/payload/src/auth/cookies.spec.ts b/packages/payload/src/auth/cookies.spec.ts index f3cc3402e3c..dbdbc4f656d 100644 --- a/packages/payload/src/auth/cookies.spec.ts +++ b/packages/payload/src/auth/cookies.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { parseCookies } from './cookies.js' describe('parseCookies', () => { diff --git a/packages/payload/src/bin/generateImportMap/generateImportMap.spec.ts b/packages/payload/src/bin/generateImportMap/generateImportMap.spec.ts index ddd1e9d0e7d..7f7c10caf71 100644 --- a/packages/payload/src/bin/generateImportMap/generateImportMap.spec.ts +++ b/packages/payload/src/bin/generateImportMap/generateImportMap.spec.ts @@ -1,3 +1,4 @@ +import { describe, beforeEach, expect, it, vitest } from 'vitest' import type { PayloadComponent } from '../../index.js' import { addPayloadComponentToImportMap } from './utilities/addPayloadComponentToImportMap.js' import { getImportMapToBaseDirPath } from './utilities/getImportMapToBaseDirPath.js' @@ -15,7 +16,7 @@ describe('addPayloadComponentToImportMap', () => { beforeEach(() => { importMap = {} imports = {} - jest.restoreAllMocks() + vitest.restoreAllMocks() }) function componentPathTest({ diff --git a/packages/payload/src/collections/config/useAsTitle.spec.ts b/packages/payload/src/collections/config/useAsTitle.spec.ts index 1d8913d6773..d77fe1c7e9f 100644 --- a/packages/payload/src/collections/config/useAsTitle.spec.ts +++ b/packages/payload/src/collections/config/useAsTitle.spec.ts @@ -3,6 +3,7 @@ import type { CollectionConfig } from '../../index.js' import { InvalidConfiguration } from '../../errors/InvalidConfiguration.js' import { sanitizeCollection } from './sanitize.js' +import { describe, it, expect } from 'vitest' describe('sanitize - collections -', () => { const config = { diff --git a/packages/payload/src/database/migrations/findMigrationDir.spec.ts b/packages/payload/src/database/migrations/findMigrationDir.spec.ts index 15c5026142b..f0f968d3c76 100644 --- a/packages/payload/src/database/migrations/findMigrationDir.spec.ts +++ b/packages/payload/src/database/migrations/findMigrationDir.spec.ts @@ -1,3 +1,4 @@ +import { afterEach, beforeEach, describe, expect, it, vitest } from 'vitest' import { findMigrationDir } from './findMigrationDir' import fs from 'fs' import path from 'path' @@ -6,7 +7,7 @@ const workDir = path.resolve(import.meta.dirname, '_tmp') describe('findMigrationDir', () => { beforeEach(() => { - const cwdSpy = jest.spyOn(process, 'cwd') + const cwdSpy = vitest.spyOn(process, 'cwd') cwdSpy.mockReturnValue(workDir) fs.mkdirSync(workDir, { recursive: true }) }) diff --git a/packages/payload/src/database/migrations/readMigrationFiles.ts b/packages/payload/src/database/migrations/readMigrationFiles.ts index 0d74492b9b1..2d25b05f84c 100644 --- a/packages/payload/src/database/migrations/readMigrationFiles.ts +++ b/packages/payload/src/database/migrations/readMigrationFiles.ts @@ -1,5 +1,4 @@ import fs from 'fs' -import { pathToFileURL } from 'node:url' import path from 'path' import type { Payload } from '../../index.js' @@ -36,11 +35,7 @@ export const readMigrationFiles = async ({ return Promise.all( files.map(async (filePath) => { - // eval used to circumvent errors bundling - let migration = - typeof require === 'function' - ? await eval(`require('${filePath.replaceAll('\\', '/')}')`) - : await eval(`import('${pathToFileURL(filePath).href}')`) + let migration = await import(filePath.replaceAll('\\', '/')) if ('default' in migration) { migration = migration.default } diff --git a/packages/payload/src/fields/config/reservedFieldNames.spec.ts b/packages/payload/src/fields/config/reservedFieldNames.spec.ts index cfaaeb1f316..cb712b3ffff 100644 --- a/packages/payload/src/fields/config/reservedFieldNames.spec.ts +++ b/packages/payload/src/fields/config/reservedFieldNames.spec.ts @@ -3,6 +3,7 @@ import type { CollectionConfig, Field } from '../../index.js' import { ReservedFieldName } from '../../errors/index.js' import { sanitizeCollection } from '../../collections/config/sanitize.js' +import { describe, it, expect } from 'vitest' describe('reservedFieldNames - collections -', () => { const config = { diff --git a/packages/payload/src/fields/config/sanitize.spec.ts b/packages/payload/src/fields/config/sanitize.spec.ts index 6871f3c605b..77666d4c7a3 100644 --- a/packages/payload/src/fields/config/sanitize.spec.ts +++ b/packages/payload/src/fields/config/sanitize.spec.ts @@ -17,6 +17,7 @@ import { } from '../../errors/index.js' import { sanitizeFields } from './sanitize.js' import { CollectionConfig } from '../../index.js' +import { describe, it, expect } from 'vitest' describe('sanitizeFields', () => { const config = {} as Config diff --git a/packages/payload/src/fields/validations.spec.ts b/packages/payload/src/fields/validations.spec.ts index e8b540a76ce..dfcdc5d2e6f 100644 --- a/packages/payload/src/fields/validations.spec.ts +++ b/packages/payload/src/fields/validations.spec.ts @@ -1,5 +1,3 @@ -import { jest } from '@jest/globals' - import type { SelectField, ValidateOptions } from './config/types.js' import { @@ -15,8 +13,9 @@ import { type PointFieldValidation, type SelectFieldValidation, } from './validations.js' +import { describe, expect, it, vitest } from 'vitest' -const t = jest.fn((string) => string) +const t = vitest.fn((string) => string) let options: ValidateOptions = { data: undefined, diff --git a/packages/payload/src/queues/operations/runJobs/runJob/importHandlerPath.ts b/packages/payload/src/queues/operations/runJobs/runJob/importHandlerPath.ts index b7d23d1f3cc..b9ed161321c 100644 --- a/packages/payload/src/queues/operations/runJobs/runJob/importHandlerPath.ts +++ b/packages/payload/src/queues/operations/runJobs/runJob/importHandlerPath.ts @@ -1,5 +1,3 @@ -import { pathToFileURL } from 'url' - import type { TaskConfig, TaskHandler, TaskType } from '../../../config/types/taskTypes.js' /** @@ -11,12 +9,7 @@ export async function importHandlerPath(path: string): Promise { let runnerModule try { - // We need to check for `require` for compatibility with outdated frameworks that do not - // properly support ESM, like Jest. This is not done to support projects without "type": "module" set - runnerModule = - typeof require === 'function' - ? await eval(`require('${runnerPath!.replaceAll('\\', '/')}')`) - : await eval(`import('${pathToFileURL(runnerPath!).href}')`) + runnerModule = await import(runnerPath!.replaceAll('\\', '/')) } catch (e) { throw new Error( `Error importing job queue handler module for path ${path}. This is an advanced feature that may require a sophisticated build pipeline, especially when using it in production or within Next.js, e.g. by calling opening the /api/payload-jobs/run endpoint. You will have to transpile the handler files separately and ensure they are available in the same location when the job is run. If you're using an endpoint to execute your jobs, it's recommended to define your handlers as functions directly in your Payload Config, or use import paths handlers outside of Next.js. Import Error: \n${e instanceof Error ? e.message : 'Unknown error'}`, diff --git a/packages/payload/src/uploads/mimeTypeValidator.spec.ts b/packages/payload/src/uploads/mimeTypeValidator.spec.ts index 895ddcc7cb8..7a9f9e488ae 100644 --- a/packages/payload/src/uploads/mimeTypeValidator.spec.ts +++ b/packages/payload/src/uploads/mimeTypeValidator.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import type { ValidateOptions } from '../fields/config/types' import { mimeTypeValidator } from './mimeTypeValidator' diff --git a/packages/payload/src/utilities/addSelectGenericsToGeneratedTypes.spec.ts b/packages/payload/src/utilities/addSelectGenericsToGeneratedTypes.spec.ts index 68eb6f3dbbf..e4327408342 100644 --- a/packages/payload/src/utilities/addSelectGenericsToGeneratedTypes.spec.ts +++ b/packages/payload/src/utilities/addSelectGenericsToGeneratedTypes.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { addSelectGenericsToGeneratedTypes } from './addSelectGenericsToGeneretedTypes.js' const INPUT_AND_OUTPUT = [ @@ -272,7 +273,7 @@ export interface Auth { declare module 'payload' { - // @ts-ignore + // @ts-ignore export interface GeneratedTypes extends Config {} } `, @@ -546,7 +547,7 @@ export interface Auth { declare module 'payload' { - // @ts-ignore + // @ts-ignore export interface GeneratedTypes extends Config {} } `, diff --git a/packages/payload/src/utilities/combineWhereConstraints.spec.ts b/packages/payload/src/utilities/combineWhereConstraints.spec.ts index c852a9477bd..4055e5a81ea 100644 --- a/packages/payload/src/utilities/combineWhereConstraints.spec.ts +++ b/packages/payload/src/utilities/combineWhereConstraints.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { Where } from '../types/index.js' import { combineWhereConstraints } from './combineWhereConstraints.js' diff --git a/packages/payload/src/utilities/configToJSONSchema.spec.ts b/packages/payload/src/utilities/configToJSONSchema.spec.ts index 5e18c61f2eb..b63fa5a99c1 100644 --- a/packages/payload/src/utilities/configToJSONSchema.spec.ts +++ b/packages/payload/src/utilities/configToJSONSchema.spec.ts @@ -1,4 +1,5 @@ import type { JSONSchema4 } from 'json-schema' +import { describe, it, expect } from 'vitest' import type { Config } from '../config/types.js' diff --git a/packages/payload/src/utilities/flattenTopLevelFields.spec.ts b/packages/payload/src/utilities/flattenTopLevelFields.spec.ts index 25ffa9154d4..61aa793af96 100644 --- a/packages/payload/src/utilities/flattenTopLevelFields.spec.ts +++ b/packages/payload/src/utilities/flattenTopLevelFields.spec.ts @@ -1,4 +1,5 @@ import { I18nClient } from '@payloadcms/translations' +import { describe, it, expect } from 'vitest' import { ClientField } from '../fields/config/client.js' import { flattenTopLevelFields } from './flattenTopLevelFields.js' diff --git a/packages/payload/src/utilities/formatAdminURL.spec.ts b/packages/payload/src/utilities/formatAdminURL.spec.ts index 73079df39db..0674e7f1fed 100644 --- a/packages/payload/src/utilities/formatAdminURL.spec.ts +++ b/packages/payload/src/utilities/formatAdminURL.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { formatAdminURL } from './formatAdminURL.js' describe('formatAdminURL', () => { diff --git a/packages/payload/src/utilities/formatLabels.spec.ts b/packages/payload/src/utilities/formatLabels.spec.ts index b2505d07504..875d8a1a37e 100644 --- a/packages/payload/src/utilities/formatLabels.spec.ts +++ b/packages/payload/src/utilities/formatLabels.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { formatLabels, toWords } from './formatLabels' describe('formatLabels', () => { diff --git a/packages/payload/src/utilities/getFieldByPath.spec.ts b/packages/payload/src/utilities/getFieldByPath.spec.ts index 12b56dff88e..d4f120f6fb0 100644 --- a/packages/payload/src/utilities/getFieldByPath.spec.ts +++ b/packages/payload/src/utilities/getFieldByPath.spec.ts @@ -1,4 +1,5 @@ import { assert } from 'ts-essentials' +import { describe, it, expect } from 'vitest' import { flattenAllFields } from './flattenAllFields.js' import { getFieldByPath } from './getFieldByPath.js' import type { FlattenedArrayField, FlattenedGroupField } from '../fields/config/types.js' diff --git a/packages/payload/src/utilities/getFieldPermissions.spec.ts b/packages/payload/src/utilities/getFieldPermissions.spec.ts index 3b258382090..06ba3b16407 100644 --- a/packages/payload/src/utilities/getFieldPermissions.spec.ts +++ b/packages/payload/src/utilities/getFieldPermissions.spec.ts @@ -1,6 +1,7 @@ import type { SanitizedDocumentPermissions } from '../auth/types.js' import { getFieldPermissions } from './getFieldPermissions.js' +import { describe, expect, it } from 'vitest' describe('getFieldPermissions with collection fallback', () => { const mockField = { diff --git a/packages/payload/src/utilities/getSafeRedirect.spec.ts b/packages/payload/src/utilities/getSafeRedirect.spec.ts index 823c8ea4a5e..9cff6cc0756 100644 --- a/packages/payload/src/utilities/getSafeRedirect.spec.ts +++ b/packages/payload/src/utilities/getSafeRedirect.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { getSafeRedirect } from './getSafeRedirect' const fallback = '/admin' // default fallback if the input is unsafe or invalid diff --git a/packages/payload/src/utilities/parseParams/index.spec.ts b/packages/payload/src/utilities/parseParams/index.spec.ts index c7a781140c6..14eaa1774d0 100644 --- a/packages/payload/src/utilities/parseParams/index.spec.ts +++ b/packages/payload/src/utilities/parseParams/index.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { parseParams, booleanParams, numberParams } from './index.js' describe('parseParams', () => { diff --git a/packages/payload/src/utilities/sanitizePermissions.spec.ts b/packages/payload/src/utilities/sanitizePermissions.spec.ts index 7c15b7a3e76..0ad37f8a16b 100644 --- a/packages/payload/src/utilities/sanitizePermissions.spec.ts +++ b/packages/payload/src/utilities/sanitizePermissions.spec.ts @@ -1,5 +1,5 @@ +import { describe, it, expect } from 'vitest' import type { CollectionPermission, Permissions } from '../auth/types.js' -import { preferencesCollectionSlug } from '../preferences/config.js' import { sanitizePermissions } from './sanitizePermissions.js' diff --git a/packages/payload/src/utilities/sanitizeUserDataForEmail.spec.ts b/packages/payload/src/utilities/sanitizeUserDataForEmail.spec.ts index 7acd931f1ae..43e31408751 100644 --- a/packages/payload/src/utilities/sanitizeUserDataForEmail.spec.ts +++ b/packages/payload/src/utilities/sanitizeUserDataForEmail.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { sanitizeUserDataForEmail } from './sanitizeUserDataForEmail' describe('sanitizeUserDataForEmail', () => { diff --git a/packages/plugin-ecommerce/src/utilities/accessComposition.spec.ts b/packages/plugin-ecommerce/src/utilities/accessComposition.spec.ts index 5638fa3cec0..02e3e2ea378 100644 --- a/packages/plugin-ecommerce/src/utilities/accessComposition.spec.ts +++ b/packages/plugin-ecommerce/src/utilities/accessComposition.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import type { Access, AccessArgs, Where } from 'payload' import { accessAND, conditional, accessOR } from './accessComposition' diff --git a/packages/plugin-ecommerce/src/utilities/defaultProductsValidation.spec.ts b/packages/plugin-ecommerce/src/utilities/defaultProductsValidation.spec.ts index 453f133164d..c680e331c4f 100644 --- a/packages/plugin-ecommerce/src/utilities/defaultProductsValidation.spec.ts +++ b/packages/plugin-ecommerce/src/utilities/defaultProductsValidation.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import type { CurrenciesConfig } from '../types/index.js' import { EUR, USD } from '../currencies/index.js' diff --git a/packages/plugin-ecommerce/src/utilities/getCollectionSlugMap.spec.ts b/packages/plugin-ecommerce/src/utilities/getCollectionSlugMap.spec.ts index f435fa4ed7f..14a38975317 100644 --- a/packages/plugin-ecommerce/src/utilities/getCollectionSlugMap.spec.ts +++ b/packages/plugin-ecommerce/src/utilities/getCollectionSlugMap.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect, vitest } from 'vitest' import type { SanitizedEcommercePluginConfig } from '../types/index.js' import { USD } from '../currencies/index.js' @@ -5,13 +6,13 @@ import { getCollectionSlugMap } from './getCollectionSlugMap' describe('getCollectionSlugMap', () => { const mockAccessConfig = { - adminOnlyFieldAccess: jest.fn(), - adminOrPublishedStatus: jest.fn(), - customerOnlyFieldAccess: jest.fn(), - isAdmin: jest.fn(), - isAuthenticated: jest.fn(), - isDocumentOwner: jest.fn(), - publicAccess: jest.fn(), + adminOnlyFieldAccess: vitest.fn(), + adminOrPublishedStatus: vitest.fn(), + customerOnlyFieldAccess: vitest.fn(), + isAdmin: vitest.fn(), + isAuthenticated: vitest.fn(), + isDocumentOwner: vitest.fn(), + publicAccess: vitest.fn(), } const baseConfig: SanitizedEcommercePluginConfig = { diff --git a/packages/plugin-ecommerce/src/utilities/sanitizePluginConfig.spec.ts b/packages/plugin-ecommerce/src/utilities/sanitizePluginConfig.spec.ts index fb50e652a86..55dcc141449 100644 --- a/packages/plugin-ecommerce/src/utilities/sanitizePluginConfig.spec.ts +++ b/packages/plugin-ecommerce/src/utilities/sanitizePluginConfig.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect, vitest } from 'vitest' import type { EcommercePluginConfig } from '../types/index.js' import { EUR, USD } from '../currencies/index.js' @@ -5,12 +6,12 @@ import { sanitizePluginConfig } from './sanitizePluginConfig' describe('sanitizePluginConfig', () => { const mockAccessConfig = { - adminOnlyFieldAccess: jest.fn(), - adminOrPublishedStatus: jest.fn(), - customerOnlyFieldAccess: jest.fn(), - isAdmin: jest.fn(), - isAuthenticated: jest.fn(), - isDocumentOwner: jest.fn(), + adminOnlyFieldAccess: vitest.fn(), + adminOrPublishedStatus: vitest.fn(), + customerOnlyFieldAccess: vitest.fn(), + isAdmin: vitest.fn(), + isAuthenticated: vitest.fn(), + isDocumentOwner: vitest.fn(), } const minimalConfig: EcommercePluginConfig = { @@ -255,7 +256,7 @@ describe('sanitizePluginConfig', () => { ...minimalConfig, carts: { allowGuestCarts: false, - cartsCollectionOverride: jest.fn() as any, + cartsCollectionOverride: vitest.fn() as any, }, } @@ -411,8 +412,8 @@ describe('sanitizePluginConfig', () => { }) it('should allow user-provided access functions to override defaults', () => { - const customIsAuthenticated = jest.fn() - const customPublicAccess = jest.fn() + const customIsAuthenticated = vitest.fn() + const customPublicAccess = vitest.fn() const config: EcommercePluginConfig = { ...minimalConfig, diff --git a/packages/plugin-sentry/jest.config.js b/packages/plugin-sentry/jest.config.js deleted file mode 100644 index b0539a17900..00000000000 --- a/packages/plugin-sentry/jest.config.js +++ /dev/null @@ -1,32 +0,0 @@ -import baseConfig from '../../jest.config.js' - -/** @type {import('jest').Config} */ -const customJestConfig = { - ...baseConfig, - setupFilesAfterEnv: null, - testMatch: ['**/src/**/?(*.)+(spec|test|it-test).[tj]s?(x)'], - testTimeout: 20000, - transform: { - '^.+\\.(t|j)sx?$': [ - '@swc/jest', - { - $schema: 'https://json.schemastore.org/swcrc', - sourceMaps: true, - exclude: ['/**/mocks'], - jsc: { - target: 'esnext', - parser: { - syntax: 'typescript', - tsx: true, - dts: true, - }, - }, - module: { - type: 'es6', - }, - }, - ], - }, -} - -export default customJestConfig diff --git a/packages/plugin-sentry/src/plugin.spec.ts b/packages/plugin-sentry/src/plugin.spec.ts index 9b09b3737ef..0d7d8d21289 100644 --- a/packages/plugin-sentry/src/plugin.spec.ts +++ b/packages/plugin-sentry/src/plugin.spec.ts @@ -1,9 +1,10 @@ import type { AfterErrorHook, AfterErrorHookArgs, Config, PayloadRequest } from 'payload' +import { randomUUID } from 'crypto' +import { describe, it, expect, vitest } from 'vitest' -import { APIError, defaults } from 'payload' +import { defaults } from 'payload' import { sentryPlugin } from './index' -import { randomUUID } from 'crypto' const mockExceptionID = randomUUID() @@ -70,7 +71,7 @@ describe('@payloadcms/plugin-sentry - unit', () => { collection: { slug: 'mock-slug' } as any, } - const captureExceptionSpy = jest.spyOn(mockSentry, 'captureException') + const captureExceptionSpy = vitest.spyOn(mockSentry, 'captureException') await hook(afterApiErrorHookArgs) diff --git a/packages/richtext-lexical/src/dependencyChecker.spec.ts b/packages/richtext-lexical/src/dependencyChecker.spec.ts index 6240b4ec93b..32fafcc5715 100644 --- a/packages/richtext-lexical/src/dependencyChecker.spec.ts +++ b/packages/richtext-lexical/src/dependencyChecker.spec.ts @@ -1,8 +1,8 @@ -import { jest } from '@jest/globals' import { lexicalTargetVersion } from './index' import { fileURLToPath } from 'url' import path from 'path' import fs from 'fs/promises' +import { describe, it, expect } from 'vitest' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) diff --git a/packages/richtext-lexical/src/features/converters/lexicalToPlaintext/convertLexicalToPlaintext.spec.ts b/packages/richtext-lexical/src/features/converters/lexicalToPlaintext/convertLexicalToPlaintext.spec.ts index d08c002335a..0c27342a514 100644 --- a/packages/richtext-lexical/src/features/converters/lexicalToPlaintext/convertLexicalToPlaintext.spec.ts +++ b/packages/richtext-lexical/src/features/converters/lexicalToPlaintext/convertLexicalToPlaintext.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import type { DefaultNodeTypes, DefaultTypedEditorState, diff --git a/packages/richtext-lexical/src/lexical/utils/url.spec.ts b/packages/richtext-lexical/src/lexical/utils/url.spec.ts index bb30401a930..798649560e1 100644 --- a/packages/richtext-lexical/src/lexical/utils/url.spec.ts +++ b/packages/richtext-lexical/src/lexical/utils/url.spec.ts @@ -1,4 +1,4 @@ -import { jest } from '@jest/globals' +import { describe, it, expect } from 'vitest' import { absoluteRegExp, relativeOrAnchorRegExp, validateUrl } from './url.js' describe('Lexical URL Regex Matchers', () => { diff --git a/packages/richtext-lexical/src/utilities/jsx/jsx.spec.ts b/packages/richtext-lexical/src/utilities/jsx/jsx.spec.ts index d6cd728bd40..7fec1f07ed0 100644 --- a/packages/richtext-lexical/src/utilities/jsx/jsx.spec.ts +++ b/packages/richtext-lexical/src/utilities/jsx/jsx.spec.ts @@ -1,3 +1,4 @@ +import { describe, it, expect } from 'vitest' import { extractPropsFromJSXPropsString } from './extractPropsFromJSXPropsString.js' import { propsToJSXString } from './jsx.js' diff --git a/packages/ui/src/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.js b/packages/ui/src/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.js index 3b9df14a1b9..0d96a536110 100644 --- a/packages/ui/src/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.js +++ b/packages/ui/src/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.js @@ -1,4 +1,5 @@ -import fieldSchemasToFormState from './index.js' +import { describe, it, expect } from 'vitest' +import { fieldSchemasToFormState } from './index.js' describe('Form - fieldSchemasToFormState', () => { const defaultValue = 'Default' @@ -11,7 +12,7 @@ describe('Form - fieldSchemasToFormState', () => { label: 'Text', }, ] - const state = await fieldSchemasToFormState({ fields: fieldSchema }) + const state = await fieldSchemasToFormState({ req: {}, fields: fieldSchema }) expect(state.text.value).toBe(defaultValue) }) it('field value overrides defaultValue - normal fields', async () => { @@ -25,7 +26,7 @@ describe('Form - fieldSchemasToFormState', () => { label: 'Text', }, ] - const state = await fieldSchemasToFormState({ data, fields: fieldSchema }) + const state = await fieldSchemasToFormState({ req: {}, data, fields: fieldSchema }) expect(state.text.value).toBe(value) }) it('populates default value from a function - normal fields', async () => { @@ -47,7 +48,12 @@ describe('Form - fieldSchemasToFormState', () => { label: 'Text', }, ] - const state = await fieldSchemasToFormState({ fields: fieldSchema, locale, user }) + const state = await fieldSchemasToFormState({ + req: { locale: 'en', user: {} }, + fields: fieldSchema, + locale, + user, + }) expect(state.text.value).toBe(defaultValue) }) }) diff --git a/packages/ui/src/utilities/normalizeRelationshipValue.spec.ts b/packages/ui/src/utilities/normalizeRelationshipValue.spec.ts index b4c3db5c636..715763c3b10 100644 --- a/packages/ui/src/utilities/normalizeRelationshipValue.spec.ts +++ b/packages/ui/src/utilities/normalizeRelationshipValue.spec.ts @@ -1,5 +1,4 @@ -import { describe, expect, it } from '@jest/globals' - +import { describe, it, expect } from 'vitest' import { normalizeRelationshipValue } from './normalizeRelationshipValue.js' describe('normalizeRelationshipValue', () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 67e2fb73941..802598bc2f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,7 +8,7 @@ overrides: copyfiles: 2.4.1 cross-env: 7.0.3 dotenv: 16.4.7 - graphql: ^16.8.1 + graphql: 16.8.1 react: 19.2.1 react-dom: 19.2.1 typescript: 5.7.3 @@ -20,15 +20,12 @@ importers: '@axe-core/playwright': specifier: 4.11.0 version: 4.11.0(playwright-core@1.56.1) - '@jest/globals': - specifier: 29.7.0 - version: 29.7.0 '@libsql/client': specifier: 0.14.0 version: 0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.5) '@next/bundle-analyzer': specifier: 15.4.7 - version: 15.4.7(bufferutil@4.0.8) + version: 15.4.7(bufferutil@4.0.8)(utf-8-validate@6.0.5) '@payloadcms/db-postgres': specifier: workspace:* version: link:packages/db-postgres @@ -46,7 +43,7 @@ importers: version: 1.56.1 '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) '@sentry/node': specifier: ^8.33.1 version: 8.37.1 @@ -65,9 +62,6 @@ importers: '@types/fs-extra': specifier: ^11.0.2 version: 11.0.4 - '@types/jest': - specifier: 29.5.12 - version: 29.5.12 '@types/minimist': specifier: 1.2.5 version: 1.2.5 @@ -109,7 +103,7 @@ importers: version: 0.31.7 drizzle-orm: specifier: 0.44.7 - version: 0.44.7(@libsql/client@0.14.0(bufferutil@4.0.8))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.11.6)(@vercel/postgres@0.9.0)(better-sqlite3@11.10.0)(gel@2.0.1)(pg@8.16.3) + version: 0.44.7(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.11.6)(@vercel/postgres@0.9.0)(better-sqlite3@11.10.0)(gel@2.0.1)(pg@8.16.3) escape-html: specifier: ^1.0.3 version: 1.0.3 @@ -128,9 +122,6 @@ importers: husky: specifier: 9.0.11 version: 9.0.11 - jest: - specifier: 29.7.0 - version: 29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0) lint-staged: specifier: 15.2.7 version: 15.2.7 @@ -142,7 +133,7 @@ importers: version: 8.15.1(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: specifier: 15.4.10 - version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) open: specifier: ^10.1.0 version: 10.1.0 @@ -200,6 +191,9 @@ importers: typescript: specifier: 5.7.3 version: 5.7.3 + vitest: + specifier: 4.0.15 + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.15.30)(jiti@2.5.1)(jsdom@26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.19.2)(yaml@2.8.1) wrangler: specifier: ~4.42.0 version: 4.42.1(bufferutil@4.0.8)(utf-8-validate@6.0.5) @@ -280,9 +274,6 @@ importers: '@types/fs-extra': specifier: ^9.0.12 version: 9.0.13 - '@types/jest': - specifier: 29.5.12 - version: 29.5.12 '@types/node': specifier: 22.15.30 version: 22.15.30 @@ -554,12 +545,6 @@ importers: packages/email-resend: devDependencies: - '@types/jest': - specifier: 29.5.12 - version: 29.5.12 - jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0) payload: specifier: workspace:* version: link:../payload @@ -568,7 +553,7 @@ importers: dependencies: '@eslint-react/eslint-plugin': specifier: 1.31.0 - version: 1.31.0(eslint@9.22.0(jiti@2.5.1))(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3) + version: 1.31.0(eslint@9.22.0(jiti@2.5.1))(ts-api-utils@2.1.0(typescript@5.7.3))(typescript@5.7.3) '@eslint/js': specifier: 9.22.0 version: 9.22.0 @@ -625,7 +610,7 @@ importers: dependencies: '@eslint-react/eslint-plugin': specifier: 1.31.0 - version: 1.31.0(eslint@9.22.0(jiti@2.5.1))(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3) + version: 1.31.0(eslint@9.22.0(jiti@2.5.1))(ts-api-utils@2.1.0(typescript@5.7.3))(typescript@5.7.3) '@eslint/js': specifier: 9.22.0 version: 9.22.0 @@ -675,11 +660,11 @@ importers: packages/graphql: dependencies: graphql: - specifier: ^16.8.1 - version: 16.9.0 + specifier: 16.8.1 + version: 16.8.1 graphql-scalars: specifier: 1.22.2 - version: 1.22.2(graphql@16.9.0) + version: 1.22.2(graphql@16.8.1) pluralize: specifier: 8.0.0 version: 8.0.0 @@ -698,7 +683,7 @@ importers: version: 0.0.33 graphql-http: specifier: ^1.22.0 - version: 1.22.2(graphql@16.9.0) + version: 1.22.2(graphql@16.8.1) payload: specifier: workspace:* version: link:../payload @@ -793,11 +778,11 @@ importers: specifier: 19.3.0 version: 19.3.0 graphql: - specifier: ^16.8.1 - version: 16.9.0 + specifier: 16.8.1 + version: 16.8.1 graphql-http: specifier: ^1.22.0 - version: 1.22.2(graphql@16.9.0) + version: 1.22.2(graphql@16.8.1) graphql-playground-html: specifier: 1.6.30 version: 1.6.30 @@ -806,7 +791,7 @@ importers: version: 2.1.0 next: specifier: ^15.4.10 - version: 15.4.10(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) path-to-regexp: specifier: 6.3.0 version: 6.3.0 @@ -911,8 +896,8 @@ importers: specifier: 4.8.1 version: 4.8.1 graphql: - specifier: ^16.8.1 - version: 16.9.0 + specifier: 16.8.1 + version: 16.8.1 http-status: specifier: 2.1.0 version: 2.1.0 @@ -1012,7 +997,7 @@ importers: version: 0.25.5 graphql-http: specifier: ^1.22.0 - version: 1.22.2(graphql@16.9.0) + version: 1.22.2(graphql@16.8.1) react-datepicker: specifier: 7.6.0 version: 7.6.0(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -1053,9 +1038,6 @@ importers: specifier: 7.0.9 version: 7.0.9 devDependencies: - '@types/jest': - specifier: 29.5.12 - version: 29.5.12 '@types/nodemailer': specifier: 7.0.2 version: 7.0.2 @@ -1209,7 +1191,7 @@ importers: version: 7.0.15 '@vercel/mcp-adapter': specifier: ^1.0.0 - version: 1.0.0(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.0.0(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) json-schema-to-zod: specifier: 2.6.1 version: 2.6.1 @@ -1293,7 +1275,7 @@ importers: dependencies: '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) '@sentry/types': specifier: ^8.33.1 version: 8.37.1 @@ -1684,7 +1666,7 @@ importers: version: link:../plugin-cloud-storage uploadthing: specifier: 7.3.0 - version: 7.3.0(express@5.0.1)(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(tailwindcss@4.1.13) + version: 7.3.0(express@5.0.1)(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(tailwindcss@4.1.13) devDependencies: payload: specifier: workspace:* @@ -1771,7 +1753,7 @@ importers: version: 2.3.0 next: specifier: ^15.2.8 || ^15.3.8 || ^15.4.10 || ^15.5.9 - version: 15.4.10(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) object-to-formdata: specifier: 4.5.1 version: 4.5.1 @@ -1873,11 +1855,11 @@ importers: specifier: 16.4.7 version: 16.4.7 graphql: - specifier: ^16.8.1 - version: 16.9.0 + specifier: 16.8.1 + version: 16.8.1 next: specifier: 15.4.10 - version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: workspace:* version: link:../../packages/payload @@ -2019,10 +2001,10 @@ importers: version: 8.6.0(react@19.2.1) geist: specifier: ^1.3.0 - version: 1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) graphql: - specifier: ^16.8.1 - version: 16.9.0 + specifier: 16.8.1 + version: 16.8.1 jsonwebtoken: specifier: 9.0.1 version: 9.0.1 @@ -2031,7 +2013,7 @@ importers: version: 0.477.0(react@19.2.1) next: specifier: 15.4.10 - version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes: specifier: 0.4.6 version: 0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -2218,19 +2200,19 @@ importers: version: 16.4.7 geist: specifier: ^1.3.0 - version: 1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) graphql: - specifier: ^16.8.1 - version: 16.9.0 + specifier: 16.8.1 + version: 16.8.1 lucide-react: specifier: ^0.378.0 version: 0.378.0(react@19.2.1) next: specifier: 15.4.10 - version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-sitemap: specifier: ^4.2.3 - version: 4.2.3(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 4.2.3(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) payload: specifier: workspace:* version: link:../../packages/payload @@ -2327,7 +2309,7 @@ importers: dependencies: recharts: specifier: 3.2.1 - version: 3.2.1(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react-is@18.3.1)(react@19.2.1)(redux@5.0.1) + version: 3.2.1(@types/react@19.1.12)(react-dom@19.2.1(react@19.2.1))(react-is@18.3.1)(react@19.2.1)(redux@5.0.1) devDependencies: '@aws-sdk/client-s3': specifier: ^3.614.0 @@ -2475,7 +2457,7 @@ importers: version: link:../packages/ui '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) '@sentry/react': specifier: ^7.77.0 version: 7.119.2(react@19.2.1) @@ -2485,15 +2467,12 @@ importers: '@stripe/stripe-js': specifier: 7.3.1 version: 7.3.1 - '@types/jest': - specifier: 29.5.12 - version: 29.5.12 '@types/react': - specifier: 19.2.1 - version: 19.2.1 + specifier: 19.1.12 + version: 19.1.12 '@types/react-dom': - specifier: 19.2.1 - version: 19.2.1(@types/react@19.2.1) + specifier: 19.1.9 + version: 19.1.9(@types/react@19.1.12) babel-plugin-react-compiler: specifier: 19.1.0-rc.3 version: 19.1.0-rc.3 @@ -2520,7 +2499,7 @@ importers: version: 0.31.7 drizzle-orm: specifier: 0.44.7 - version: 0.44.7(@libsql/client@0.14.0(bufferutil@4.0.8))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.11.6)(@vercel/postgres@0.9.0)(better-sqlite3@11.10.0)(gel@2.0.1)(pg@8.16.3) + version: 0.44.7(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.11.6)(@vercel/postgres@0.9.0)(better-sqlite3@11.10.0)(gel@2.0.1)(pg@8.16.3) escape-html: specifier: 1.0.3 version: 1.0.3 @@ -2536,9 +2515,6 @@ importers: http-status: specifier: 2.1.0 version: 2.1.0 - jest: - specifier: 29.7.0 - version: 29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0) jwt-decode: specifier: 4.0.0 version: 4.0.0 @@ -2547,7 +2523,7 @@ importers: version: 8.15.1(@aws-sdk/credential-providers@3.687.0(@aws-sdk/client-sso-oidc@3.687.0(@aws-sdk/client-sts@3.687.0)))(socks@2.8.3) next: specifier: 15.4.10 - version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) nodemailer: specifier: 7.0.9 version: 7.0.9 @@ -2593,6 +2569,9 @@ importers: uuid: specifier: 10.0.0 version: 10.0.0 + vitest: + specifier: 4.0.15 + version: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.15.30)(jiti@2.5.1)(jsdom@26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1) wrangler: specifier: ~4.42.0 version: 4.42.1(bufferutil@4.0.8)(utf-8-validate@6.0.5) @@ -3302,10 +3281,6 @@ packages: resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==} engines: {node: '>=6.9.0'} - '@babel/generator@7.26.5': - resolution: {integrity: sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==} - engines: {node: '>=6.9.0'} - '@babel/generator@7.27.5': resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==} engines: {node: '>=6.9.0'} @@ -3524,12 +3499,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.26.0': - resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.27.1': resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} engines: {node: '>=6.9.0'} @@ -3546,12 +3515,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.25.9': - resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} engines: {node: '>=6.9.0'} @@ -3600,12 +3563,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.25.9': - resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.27.1': resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} engines: {node: '>=6.9.0'} @@ -4804,6 +4761,12 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/regexpp@4.12.1': resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -5445,6 +5408,9 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} @@ -6692,101 +6658,51 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.43.0': - resolution: {integrity: sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==} - cpu: [arm] - os: [android] - '@rollup/rollup-android-arm-eabi@4.52.3': resolution: {integrity: sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.43.0': - resolution: {integrity: sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==} - cpu: [arm64] - os: [android] - '@rollup/rollup-android-arm64@4.52.3': resolution: {integrity: sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.43.0': - resolution: {integrity: sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==} - cpu: [arm64] - os: [darwin] - '@rollup/rollup-darwin-arm64@4.52.3': resolution: {integrity: sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.43.0': - resolution: {integrity: sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==} - cpu: [x64] - os: [darwin] - '@rollup/rollup-darwin-x64@4.52.3': resolution: {integrity: sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.43.0': - resolution: {integrity: sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==} - cpu: [arm64] - os: [freebsd] - '@rollup/rollup-freebsd-arm64@4.52.3': resolution: {integrity: sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.43.0': - resolution: {integrity: sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==} - cpu: [x64] - os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.3': resolution: {integrity: sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.43.0': - resolution: {integrity: sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==} - cpu: [arm] - os: [linux] - '@rollup/rollup-linux-arm-gnueabihf@4.52.3': resolution: {integrity: sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.43.0': - resolution: {integrity: sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==} - cpu: [arm] - os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.52.3': resolution: {integrity: sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.43.0': - resolution: {integrity: sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==} - cpu: [arm64] - os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.52.3': resolution: {integrity: sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.43.0': - resolution: {integrity: sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==} - cpu: [arm64] - os: [linux] - '@rollup/rollup-linux-arm64-musl@4.52.3': resolution: {integrity: sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==} cpu: [arm64] @@ -6797,66 +6713,31 @@ packages: cpu: [loong64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.43.0': - resolution: {integrity: sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.43.0': - resolution: {integrity: sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==} - cpu: [ppc64] - os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.52.3': resolution: {integrity: sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.43.0': - resolution: {integrity: sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==} - cpu: [riscv64] - os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.52.3': resolution: {integrity: sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.43.0': - resolution: {integrity: sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==} - cpu: [riscv64] - os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.52.3': resolution: {integrity: sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.43.0': - resolution: {integrity: sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==} - cpu: [s390x] - os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.52.3': resolution: {integrity: sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.43.0': - resolution: {integrity: sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==} - cpu: [x64] - os: [linux] - '@rollup/rollup-linux-x64-gnu@4.52.3': resolution: {integrity: sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.43.0': - resolution: {integrity: sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==} - cpu: [x64] - os: [linux] - '@rollup/rollup-linux-x64-musl@4.52.3': resolution: {integrity: sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==} cpu: [x64] @@ -6867,21 +6748,11 @@ packages: cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.43.0': - resolution: {integrity: sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==} - cpu: [arm64] - os: [win32] - '@rollup/rollup-win32-arm64-msvc@4.52.3': resolution: {integrity: sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.43.0': - resolution: {integrity: sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==} - cpu: [ia32] - os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.3': resolution: {integrity: sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==} cpu: [ia32] @@ -6892,11 +6763,6 @@ packages: cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.43.0': - resolution: {integrity: sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==} - cpu: [x64] - os: [win32] - '@rollup/rollup-win32-x64-msvc@4.52.3': resolution: {integrity: sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==} cpu: [x64] @@ -8128,9 +7994,6 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - '@types/jest@29.5.12': - resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -8212,6 +8075,11 @@ packages: '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + '@types/react-dom@19.1.9': + resolution: {integrity: sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==} + peerDependencies: + '@types/react': ^19.0.0 + '@types/react-dom@19.2.1': resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} peerDependencies: @@ -8220,6 +8088,9 @@ packages: '@types/react-transition-group@4.4.11': resolution: {integrity: sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==} + '@types/react@19.1.12': + resolution: {integrity: sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==} + '@types/react@19.2.1': resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} @@ -8286,6 +8157,12 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: 5.7.3 + '@typescript-eslint/project-service@8.46.2': + resolution: {integrity: sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: 5.7.3 + '@typescript-eslint/scope-manager@8.14.0': resolution: {integrity: sha512-aBbBrnW9ARIDn92Zbo7rguLnqQ/pOrUguVpbUwzOhkFg2npFDwTgPGqFqE0H5feXcOoJOfX3SxlJaKEVtq54dw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -8294,6 +8171,16 @@ packages: resolution: {integrity: sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.46.2': + resolution: {integrity: sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.46.2': + resolution: {integrity: sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: 5.7.3 + '@typescript-eslint/type-utils@8.26.1': resolution: {integrity: sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -8309,6 +8196,10 @@ packages: resolution: {integrity: sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.46.2': + resolution: {integrity: sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.14.0': resolution: {integrity: sha512-OPXPLYKGZi9XS/49rdaCbR5j/S14HazviBlUQFvSKz3npr3NikF+mrgK7CFVur6XEt95DZp/cmke9d5i3vtVnQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -8324,6 +8215,12 @@ packages: peerDependencies: typescript: 5.7.3 + '@typescript-eslint/typescript-estree@8.46.2': + resolution: {integrity: sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: 5.7.3 + '@typescript-eslint/utils@8.14.0': resolution: {integrity: sha512-OGqj6uB8THhrHj0Fk27DcHPojW7zKwKkPmHXHvQ58pLYp4hy8CSUdTKykKeh+5vFqTTVmjz0zCOOPKRovdsgHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -8337,6 +8234,13 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: 5.7.3 + '@typescript-eslint/utils@8.46.2': + resolution: {integrity: sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: 5.7.3 + '@typescript-eslint/visitor-keys@8.14.0': resolution: {integrity: sha512-vG0XZo8AdTH9OE6VFRwAZldNc7qtJ/6NLGWak+BtENuEUXGZgFpihILPiBvKXvJ2nFu27XNGC6rKiwuaoMbYzQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -8345,6 +8249,10 @@ packages: resolution: {integrity: sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.46.2': + resolution: {integrity: sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@unrs/resolver-binding-android-arm-eabi@1.9.0': resolution: {integrity: sha512-h1T2c2Di49ekF2TE8ZCoJkb+jwETKUIPDJ/nO3tJBKlLFPu+fyd93f0rGP/BvArKx2k2HlRM4kqkNarj3dvZlg==} cpu: [arm] @@ -8476,6 +8384,9 @@ packages: '@vitest/expect@3.2.3': resolution: {integrity: sha512-W2RH2TPWVHA1o7UmaFKISPvdicFJH+mjykctJFoAkUw+SPTJTGjUNdKscFBrqM7IPnCVu6zihtKYa7TkZS1dkQ==} + '@vitest/expect@4.0.15': + resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} + '@vitest/mocker@3.2.3': resolution: {integrity: sha512-cP6fIun+Zx8he4rbWvi+Oya6goKQDZK+Yq4hhlggwQBbrlOQ4qtZ+G4nxB6ZnzI9lyIb+JnvyiJnPC2AGbKSPA==} peerDependencies: @@ -8487,21 +8398,47 @@ packages: vite: optional: true + '@vitest/mocker@4.0.15': + resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/pretty-format@3.2.3': resolution: {integrity: sha512-yFglXGkr9hW/yEXngO+IKMhP0jxyFw2/qys/CK4fFUZnSltD+MU7dVYGrH8rvPcK/O6feXQA+EU33gjaBBbAng==} + '@vitest/pretty-format@4.0.15': + resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} + '@vitest/runner@3.2.3': resolution: {integrity: sha512-83HWYisT3IpMaU9LN+VN+/nLHVBCSIUKJzGxC5RWUOsK1h3USg7ojL+UXQR3b4o4UBIWCYdD2fxuzM7PQQ1u8w==} + '@vitest/runner@4.0.15': + resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} + '@vitest/snapshot@3.2.3': resolution: {integrity: sha512-9gIVWx2+tysDqUmmM1L0hwadyumqssOL1r8KJipwLx5JVYyxvVRfxvMq7DaWbZZsCqZnu/dZedaZQh4iYTtneA==} + '@vitest/snapshot@4.0.15': + resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} + '@vitest/spy@3.2.3': resolution: {integrity: sha512-JHu9Wl+7bf6FEejTCREy+DmgWe+rQKbK+y32C/k5f4TBIAlijhJbRBIRIOCEpVevgRsCQR2iHRUH2/qKVM/plw==} + '@vitest/spy@4.0.15': + resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} + '@vitest/utils@3.2.3': resolution: {integrity: sha512-4zFBCU5Pf+4Z6v+rwnZ1HU1yzOKKvDkMXZrymE2PBlbjKJRlrOxbvpfPSvJTGRIwGoahaOGvp+kbCoxifhzJ1Q==} + '@vitest/utils@4.0.15': + resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} + '@vue/compiler-core@3.5.12': resolution: {integrity: sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==} @@ -9151,6 +9088,10 @@ packages: resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} engines: {node: '>=12'} + chai@6.2.1: + resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + engines: {node: '>=18'} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -9594,6 +9535,15 @@ packages: supports-color: optional: true + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debuglog@1.0.1: resolution: {integrity: sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. @@ -10312,6 +10262,10 @@ packages: resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@9.22.0: resolution: {integrity: sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -10423,6 +10377,10 @@ packages: resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} engines: {node: '>=12.0.0'} + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + engines: {node: '>=12.0.0'} + expect@29.7.0: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -10525,6 +10483,15 @@ packages: picomatch: optional: true + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + fetch-blob@3.2.0: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} @@ -10884,7 +10851,7 @@ packages: resolution: {integrity: sha512-OpUJJoefHlyfYoOyhzIVjKxFPIDylmX34wy2y8M/i9i+DcQTGYmuThLGenuS92tFRzJnAXO2HJYQoz8O9TLcEg==} engines: {node: '>=12'} peerDependencies: - graphql: ^16.8.1 + graphql: 16.8.1 graphql-playground-html@1.6.30: resolution: {integrity: sha512-tpCujhsJMva4aqE8ULnF7/l3xw4sNRZcSHu+R00VV+W0mfp+Q20Plvcrp+5UXD+2yS6oyCXncA+zoQJQqhGCEw==} @@ -10893,10 +10860,10 @@ packages: resolution: {integrity: sha512-my9FB4GtghqXqi/lWSVAOPiTzTnnEzdOXCsAC2bb5V7EFNQjVjwy3cSSbUvgYOtDuDibd+ZsCDhz+4eykYOlhQ==} engines: {node: '>=10'} peerDependencies: - graphql: ^16.8.1 + graphql: 16.8.1 - graphql@16.9.0: - resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} + graphql@16.8.1: + resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} gtoken@7.1.0: @@ -11932,6 +11899,9 @@ packages: magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magic-string@0.30.8: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} engines: {node: '>=12'} @@ -12515,6 +12485,9 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + ofetch@1.4.1: resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} @@ -12757,6 +12730,10 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + pidtree@0.6.0: resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} engines: {node: '>=0.10'} @@ -13409,11 +13386,6 @@ packages: engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true - rollup@4.43.0: - resolution: {integrity: sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - rollup@4.52.3: resolution: {integrity: sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -13947,6 +13919,9 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} @@ -14300,6 +14275,10 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + tinyglobby@0.2.10: resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} engines: {node: '>=12.0.0'} @@ -14308,6 +14287,10 @@ packages: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + tinypool@1.1.0: resolution: {integrity: sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==} engines: {node: ^18.0.0 || >=20.0.0} @@ -14316,6 +14299,10 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} + tinyspy@4.0.3: resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} engines: {node: '>=14.0.0'} @@ -14389,6 +14376,12 @@ packages: peerDependencies: typescript: 5.7.3 + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: 5.7.3 + ts-essentials@10.0.3: resolution: {integrity: sha512-/FrVAZ76JLTWxJOERk04fm8hYENDo0PWSP3YLQKxevLwWtxemGcl5JJEzN4iqfDlRve0ckyfFaOBu4xbNH/wZw==} peerDependencies: @@ -14878,6 +14871,40 @@ packages: jsdom: optional: true + vitest@4.0.15: + resolution: {integrity: sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.15 + '@vitest/browser-preview': 4.0.15 + '@vitest/browser-webdriverio': 4.0.15 + '@vitest/ui': 4.0.15 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vue@3.5.12: resolution: {integrity: sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==} peerDependencies: @@ -16931,14 +16958,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.26.5': - dependencies: - '@babel/parser': 7.27.5 - '@babel/types': 7.27.3 - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 3.0.2 - '@babel/generator@7.27.5': dependencies: '@babel/parser': 7.27.5 @@ -17204,32 +17223,31 @@ snapshots: dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 @@ -17239,16 +17257,13 @@ snapshots: dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.3)': dependencies: @@ -17259,46 +17274,49 @@ snapshots: dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 + optional: true '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.3)': dependencies: @@ -17829,7 +17847,8 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@bcoe/v8-coverage@0.2.3': {} + '@bcoe/v8-coverage@0.2.3': + optional: true '@bufbuild/protobuf@2.2.2': {} @@ -18359,6 +18378,11 @@ snapshots: eslint: 9.22.0(jiti@2.5.1) eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.0(eslint@9.22.0(jiti@2.5.1))': + dependencies: + eslint: 9.22.0(jiti@2.5.1) + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.1': {} '@eslint-react/ast@1.31.0(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3)': @@ -18394,7 +18418,7 @@ snapshots: '@eslint-react/eff@1.31.0': {} - '@eslint-react/eslint-plugin@1.31.0(eslint@9.22.0(jiti@2.5.1))(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3)': + '@eslint-react/eslint-plugin@1.31.0(eslint@9.22.0(jiti@2.5.1))(ts-api-utils@2.1.0(typescript@5.7.3))(typescript@5.7.3)': dependencies: '@eslint-react/eff': 1.31.0 '@eslint-react/shared': 1.31.0(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) @@ -18408,7 +18432,7 @@ snapshots: eslint-plugin-react-hooks-extra: 1.31.0(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) eslint-plugin-react-naming-convention: 1.31.0(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) eslint-plugin-react-web-api: 1.31.0(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) - eslint-plugin-react-x: 1.31.0(eslint@9.22.0(jiti@2.5.1))(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3) + eslint-plugin-react-x: 1.31.0(eslint@9.22.0(jiti@2.5.1))(ts-api-utils@2.1.0(typescript@5.7.3))(typescript@5.7.3) optionalDependencies: typescript: 5.7.3 transitivePeerDependencies: @@ -18876,8 +18900,10 @@ snapshots: get-package-type: 0.1.0 js-yaml: 3.14.1 resolve-from: 5.0.0 + optional: true - '@istanbuljs/schema@0.1.3': {} + '@istanbuljs/schema@0.1.3': + optional: true '@jest/console@29.7.0': dependencies: @@ -18887,6 +18913,7 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 + optional: true '@jest/core@29.7.0(babel-plugin-macros@3.1.0)': dependencies: @@ -18922,6 +18949,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true '@jest/create-cache-key-function@30.2.0': dependencies: @@ -18933,10 +18961,12 @@ snapshots: '@jest/types': 29.6.3 '@types/node': 22.15.30 jest-mock: 29.7.0 + optional: true '@jest/expect-utils@29.7.0': dependencies: jest-get-type: 29.6.3 + optional: true '@jest/expect@29.7.0': dependencies: @@ -18944,6 +18974,7 @@ snapshots: jest-snapshot: 29.7.0 transitivePeerDependencies: - supports-color + optional: true '@jest/fake-timers@29.7.0': dependencies: @@ -18953,6 +18984,7 @@ snapshots: jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 + optional: true '@jest/globals@29.7.0': dependencies: @@ -18962,6 +18994,7 @@ snapshots: jest-mock: 29.7.0 transitivePeerDependencies: - supports-color + optional: true '@jest/pattern@30.0.1': dependencies: @@ -18996,10 +19029,12 @@ snapshots: v8-to-istanbul: 9.3.0 transitivePeerDependencies: - supports-color + optional: true '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 + optional: true '@jest/schemas@30.0.5': dependencies: @@ -19010,6 +19045,7 @@ snapshots: '@jridgewell/trace-mapping': 0.3.25 callsites: 3.1.0 graceful-fs: 4.2.11 + optional: true '@jest/test-result@29.7.0': dependencies: @@ -19017,6 +19053,7 @@ snapshots: '@jest/types': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 collect-v8-coverage: 1.0.2 + optional: true '@jest/test-sequencer@29.7.0': dependencies: @@ -19024,6 +19061,7 @@ snapshots: graceful-fs: 4.2.11 jest-haste-map: 29.7.0 slash: 3.0.0 + optional: true '@jest/transform@29.7.0': dependencies: @@ -19039,11 +19077,12 @@ snapshots: jest-regex-util: 29.6.3 jest-util: 29.7.0 micromatch: 4.0.8 - pirates: 4.0.6 + pirates: 4.0.7 slash: 3.0.0 write-file-atomic: 4.0.2 transitivePeerDependencies: - supports-color + optional: true '@jest/types@29.6.3': dependencies: @@ -19053,6 +19092,7 @@ snapshots: '@types/node': 22.15.30 '@types/yargs': 17.0.33 chalk: 4.1.2 + optional: true '@jest/types@30.2.0': dependencies: @@ -19081,6 +19121,8 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -19460,9 +19502,9 @@ snapshots: dependencies: '@types/pg': 8.11.6 - '@next/bundle-analyzer@15.4.7(bufferutil@4.0.8)': + '@next/bundle-analyzer@15.4.7(bufferutil@4.0.8)(utf-8-validate@6.0.5)': dependencies: - webpack-bundle-analyzer: 4.10.1(bufferutil@4.0.8) + webpack-bundle-analyzer: 4.10.1(bufferutil@4.0.8)(utf-8-validate@6.0.5) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -20351,7 +20393,7 @@ snapshots: dependencies: '@redis/client': 1.6.1 - '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.2.1)(react@19.2.1)(redux@5.0.1))(react@19.2.1)': + '@reduxjs/toolkit@2.9.0(react-redux@9.2.0(@types/react@19.1.12)(react@19.2.1)(redux@5.0.1))(react@19.2.1)': dependencies: '@standard-schema/spec': 1.0.0 '@standard-schema/utils': 0.3.0 @@ -20361,7 +20403,7 @@ snapshots: reselect: 5.1.1 optionalDependencies: react: 19.2.1 - react-redux: 9.2.0(@types/react@19.2.1)(react@19.2.1)(redux@5.0.1) + react-redux: 9.2.0(@types/react@19.1.12)(react@19.2.1)(redux@5.0.1) '@rolldown/pluginutils@1.0.0-beta.11': {} @@ -20384,129 +20426,69 @@ snapshots: optionalDependencies: rollup: 3.29.5 - '@rollup/rollup-android-arm-eabi@4.43.0': - optional: true - '@rollup/rollup-android-arm-eabi@4.52.3': optional: true - '@rollup/rollup-android-arm64@4.43.0': - optional: true - '@rollup/rollup-android-arm64@4.52.3': optional: true - '@rollup/rollup-darwin-arm64@4.43.0': - optional: true - '@rollup/rollup-darwin-arm64@4.52.3': optional: true - '@rollup/rollup-darwin-x64@4.43.0': - optional: true - - '@rollup/rollup-darwin-x64@4.52.3': - optional: true - - '@rollup/rollup-freebsd-arm64@4.43.0': + '@rollup/rollup-darwin-x64@4.52.3': optional: true '@rollup/rollup-freebsd-arm64@4.52.3': optional: true - '@rollup/rollup-freebsd-x64@4.43.0': - optional: true - '@rollup/rollup-freebsd-x64@4.52.3': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.43.0': - optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.43.0': - optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.3': optional: true - '@rollup/rollup-linux-arm64-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.43.0': - optional: true - '@rollup/rollup-linux-arm64-musl@4.52.3': optional: true '@rollup/rollup-linux-loong64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.43.0': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-riscv64-musl@4.43.0': - optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.3': optional: true - '@rollup/rollup-linux-s390x-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.43.0': - optional: true - '@rollup/rollup-linux-x64-gnu@4.52.3': optional: true - '@rollup/rollup-linux-x64-musl@4.43.0': - optional: true - '@rollup/rollup-linux-x64-musl@4.52.3': optional: true '@rollup/rollup-openharmony-arm64@4.52.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.43.0': - optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.3': optional: true - '@rollup/rollup-win32-ia32-msvc@4.43.0': - optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.3': optional: true '@rollup/rollup-win32-x64-gnu@4.52.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.43.0': - optional: true - '@rollup/rollup-win32-x64-msvc@4.52.3': optional: true @@ -20653,7 +20635,36 @@ snapshots: '@sentry/utils': 7.119.2 localforage: 1.10.0 - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.27.0 + '@rollup/plugin-commonjs': 26.0.1(rollup@3.29.5) + '@sentry-internal/browser-utils': 8.37.1 + '@sentry/core': 8.37.1 + '@sentry/node': 8.37.1 + '@sentry/opentelemetry': 8.37.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.27.0) + '@sentry/react': 8.37.1(react@19.2.1) + '@sentry/types': 8.37.1 + '@sentry/utils': 8.37.1 + '@sentry/vercel-edge': 8.37.1 + '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.15.3)) + chalk: 3.0.0 + next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + resolve: 1.22.8 + rollup: 3.29.5 + stacktrace-parser: 0.1.10 + transitivePeerDependencies: + - '@opentelemetry/core' + - '@opentelemetry/instrumentation' + - '@opentelemetry/sdk-trace-base' + - encoding + - react + - supports-color + - webpack + + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -20669,7 +20680,7 @@ snapshots: '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.15.3)) chalk: 3.0.0 - next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -20682,7 +20693,7 @@ snapshots: - supports-color - webpack - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': + '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -20698,7 +20709,7 @@ snapshots: '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.15.3)) chalk: 3.0.0 - next: 15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -20816,7 +20827,8 @@ snapshots: - encoding - supports-color - '@sinclair/typebox@0.27.8': {} + '@sinclair/typebox@0.27.8': + optional: true '@sinclair/typebox@0.34.41': {} @@ -20837,10 +20849,12 @@ snapshots: '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 + optional: true '@sinonjs/fake-timers@10.3.0': dependencies: '@sinonjs/commons': 3.0.1 + optional: true '@smithy/abort-controller@2.2.0': dependencies: @@ -22250,6 +22264,7 @@ snapshots: '@types/graceful-fs@4.1.9': dependencies: '@types/node': 22.15.30 + optional: true '@types/hast@3.0.4': dependencies: @@ -22269,11 +22284,6 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 - '@types/jest@29.5.12': - dependencies: - expect: 29.7.0 - pretty-format: 29.7.0 - '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -22382,6 +22392,10 @@ snapshots: '@types/range-parser@1.2.7': {} + '@types/react-dom@19.1.9(@types/react@19.1.12)': + dependencies: + '@types/react': 19.1.12 + '@types/react-dom@19.2.1(@types/react@19.2.1)': dependencies: '@types/react': 19.2.1 @@ -22390,6 +22404,10 @@ snapshots: dependencies: '@types/react': 19.2.1 + '@types/react@19.1.12': + dependencies: + csstype: 3.1.3 + '@types/react@19.2.1': dependencies: csstype: 3.1.3 @@ -22410,7 +22428,8 @@ snapshots: '@types/shimmer@1.2.0': {} - '@types/stack-utils@2.0.3': {} + '@types/stack-utils@2.0.3': + optional: true '@types/to-snake-case@1.0.0': {} @@ -22469,6 +22488,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.46.2(typescript@5.7.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.7.3) + '@typescript-eslint/types': 8.46.2 + debug: 4.4.3 + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.14.0': dependencies: '@typescript-eslint/types': 8.14.0 @@ -22479,6 +22507,15 @@ snapshots: '@typescript-eslint/types': 8.26.1 '@typescript-eslint/visitor-keys': 8.26.1 + '@typescript-eslint/scope-manager@8.46.2': + dependencies: + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/visitor-keys': 8.46.2 + + '@typescript-eslint/tsconfig-utils@8.46.2(typescript@5.7.3)': + dependencies: + typescript: 5.7.3 + '@typescript-eslint/type-utils@8.26.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3)': dependencies: '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.7.3) @@ -22494,6 +22531,8 @@ snapshots: '@typescript-eslint/types@8.26.1': {} + '@typescript-eslint/types@8.46.2': {} + '@typescript-eslint/typescript-estree@8.14.0(typescript@5.7.3)': dependencies: '@typescript-eslint/types': 8.14.0 @@ -22523,6 +22562,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.46.2(typescript@5.7.3)': + dependencies: + '@typescript-eslint/project-service': 8.46.2(typescript@5.7.3) + '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.7.3) + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/visitor-keys': 8.46.2 + debug: 4.4.3 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.2 + ts-api-utils: 2.1.0(typescript@5.7.3) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.14.0(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3)': dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.5.1)) @@ -22545,6 +22600,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.46.2(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.22.0(jiti@2.5.1)) + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.7.3) + eslint: 9.22.0(jiti@2.5.1) + typescript: 5.7.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@8.14.0': dependencies: '@typescript-eslint/types': 8.14.0 @@ -22555,6 +22621,11 @@ snapshots: '@typescript-eslint/types': 8.26.1 eslint-visitor-keys: 4.2.0 + '@typescript-eslint/visitor-keys@8.46.2': + dependencies: + '@typescript-eslint/types': 8.46.2 + eslint-visitor-keys: 4.2.1 + '@unrs/resolver-binding-android-arm-eabi@1.9.0': optional: true @@ -22631,12 +22702,12 @@ snapshots: '@vercel/git-hooks@1.0.0': {} - '@vercel/mcp-adapter@1.0.0(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))': + '@vercel/mcp-adapter@1.0.0(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))': dependencies: '@modelcontextprotocol/sdk': 1.24.3(zod@3.25.76) - mcp-handler: 1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + mcp-handler: 1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) optionalDependencies: - next: 15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) '@vercel/postgres@0.9.0': dependencies: @@ -22677,6 +22748,15 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 + '@vitest/expect@4.0.15': + dependencies: + '@standard-schema/spec': 1.0.0 + '@types/chai': 5.2.2 + '@vitest/spy': 4.0.15 + '@vitest/utils': 4.0.15 + chai: 6.2.1 + tinyrainbow: 3.0.3 + '@vitest/mocker@3.2.3(vite@6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.3 @@ -22693,32 +22773,70 @@ snapshots: optionalDependencies: vite: 6.3.5(@types/node@22.5.4)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1) + '@vitest/mocker@4.0.15(vite@6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.19.2)(yaml@2.8.1))': + dependencies: + '@vitest/spy': 4.0.15 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.19.2)(yaml@2.8.1) + + '@vitest/mocker@4.0.15(vite@6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + '@vitest/spy': 4.0.15 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1) + '@vitest/pretty-format@3.2.3': dependencies: tinyrainbow: 2.0.0 + '@vitest/pretty-format@4.0.15': + dependencies: + tinyrainbow: 3.0.3 + '@vitest/runner@3.2.3': dependencies: '@vitest/utils': 3.2.3 pathe: 2.0.3 strip-literal: 3.0.0 + '@vitest/runner@4.0.15': + dependencies: + '@vitest/utils': 4.0.15 + pathe: 2.0.3 + '@vitest/snapshot@3.2.3': dependencies: '@vitest/pretty-format': 3.2.3 magic-string: 0.30.17 pathe: 2.0.3 + '@vitest/snapshot@4.0.15': + dependencies: + '@vitest/pretty-format': 4.0.15 + magic-string: 0.30.21 + pathe: 2.0.3 + '@vitest/spy@3.2.3': dependencies: tinyspy: 4.0.3 + '@vitest/spy@4.0.15': {} + '@vitest/utils@3.2.3': dependencies: '@vitest/pretty-format': 3.2.3 loupe: 3.1.3 tinyrainbow: 2.0.0 + '@vitest/utils@4.0.15': + dependencies: + '@vitest/pretty-format': 4.0.15 + tinyrainbow: 3.0.3 + '@vue/compiler-core@3.5.12': dependencies: '@babel/parser': 7.26.7 @@ -23045,6 +23163,7 @@ snapshots: argparse@1.0.10: dependencies: sprintf-js: 1.0.3 + optional: true argparse@2.0.1: {} @@ -23212,6 +23331,7 @@ snapshots: slash: 3.0.0 transitivePeerDependencies: - supports-color + optional: true babel-plugin-istanbul@6.1.1: dependencies: @@ -23222,6 +23342,7 @@ snapshots: test-exclude: 6.0.0 transitivePeerDependencies: - supports-color + optional: true babel-plugin-jest-hoist@29.6.3: dependencies: @@ -23229,6 +23350,7 @@ snapshots: '@babel/types': 7.27.3 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.6 + optional: true babel-plugin-macros@3.1.0: dependencies: @@ -23275,7 +23397,7 @@ snapshots: '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.27.3) '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.27.3) '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.27.3) - '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.27.3) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.27.3) '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.27.3) '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.27.3) '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.27.3) @@ -23286,12 +23408,14 @@ snapshots: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.27.3) '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.27.3) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.27.3) + optional: true babel-preset-jest@29.6.3(@babel/core@7.27.3): dependencies: '@babel/core': 7.27.3 babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.3) + optional: true balanced-match@1.0.2: {} @@ -23407,6 +23531,7 @@ snapshots: bser@2.1.1: dependencies: node-int64: 0.4.0 + optional: true bson-objectid@2.0.4: {} @@ -23512,7 +23637,8 @@ snapshots: camelcase-css@2.0.1: {} - camelcase@5.3.1: {} + camelcase@5.3.1: + optional: true camelcase@6.3.0: {} @@ -23528,6 +23654,8 @@ snapshots: loupe: 3.1.3 pathval: 2.0.0 + chai@6.2.1: {} + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -23565,7 +23693,8 @@ snapshots: transitivePeerDependencies: - magicast - char-regex@1.0.2: {} + char-regex@1.0.2: + optional: true character-entities-html4@2.1.0: {} @@ -23599,7 +23728,8 @@ snapshots: chrome-trace-event@1.0.4: {} - ci-info@3.9.0: {} + ci-info@3.9.0: + optional: true ci-info@4.1.0: {} @@ -23637,6 +23767,7 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + optional: true cliui@9.0.1: dependencies: @@ -23660,11 +23791,13 @@ snapshots: cluster-key-slot@1.1.2: {} - co@4.6.0: {} + co@4.6.0: + optional: true code-block-writer@12.0.0: {} - collect-v8-coverage@1.0.2: {} + collect-v8-coverage@1.0.2: + optional: true color-convert@1.9.3: dependencies: @@ -23801,6 +23934,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true croner@9.1.0: {} @@ -23948,6 +24082,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.3: + dependencies: + ms: 2.1.3 + debuglog@1.0.1: {} decimal.js-light@2.5.1: {} @@ -23965,6 +24103,7 @@ snapshots: dedent@1.5.3(babel-plugin-macros@3.1.0): optionalDependencies: babel-plugin-macros: 3.1.0 + optional: true deep-eql@5.0.2: {} @@ -24032,7 +24171,8 @@ snapshots: detect-libc@2.0.4: {} - detect-newline@3.1.0: {} + detect-newline@3.1.0: + optional: true detect-newline@4.0.1: {} @@ -24049,7 +24189,8 @@ snapshots: didyoumean@1.2.2: {} - diff-sequences@29.6.3: {} + diff-sequences@29.6.3: + optional: true dir-glob@3.0.1: dependencies: @@ -24096,7 +24237,7 @@ snapshots: gel: 2.0.1 pg: 8.16.3 - drizzle-orm@0.44.7(@libsql/client@0.14.0(bufferutil@4.0.8))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.11.6)(@vercel/postgres@0.9.0)(better-sqlite3@11.10.0)(gel@2.0.1)(pg@8.16.3): + drizzle-orm@0.44.7(@libsql/client@0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.11.6)(@vercel/postgres@0.9.0)(better-sqlite3@11.10.0)(gel@2.0.1)(pg@8.16.3): optionalDependencies: '@libsql/client': 0.14.0(bufferutil@4.0.8)(utf-8-validate@6.0.5) '@opentelemetry/api': 1.9.0 @@ -24161,7 +24302,8 @@ snapshots: embla-carousel@8.6.0: {} - emittery@0.13.1: {} + emittery@0.13.1: + optional: true emoji-regex@10.4.0: {} @@ -24654,7 +24796,7 @@ snapshots: eslint-plugin-jest@28.11.0(@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(jest@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0))(typescript@5.7.3): dependencies: - '@typescript-eslint/utils': 8.14.0(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) + '@typescript-eslint/utils': 8.46.2(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) eslint: 9.22.0(jiti@2.5.1) optionalDependencies: '@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) @@ -24817,7 +24959,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-react-x@1.31.0(eslint@9.22.0(jiti@2.5.1))(ts-api-utils@2.0.1(typescript@5.7.3))(typescript@5.7.3): + eslint-plugin-react-x@1.31.0(eslint@9.22.0(jiti@2.5.1))(ts-api-utils@2.1.0(typescript@5.7.3))(typescript@5.7.3): dependencies: '@eslint-react/ast': 1.31.0(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) '@eslint-react/core': 1.31.0(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) @@ -24834,7 +24976,7 @@ snapshots: string-ts: 2.2.1 ts-pattern: 5.6.2 optionalDependencies: - ts-api-utils: 2.0.1(typescript@5.7.3) + ts-api-utils: 2.1.0(typescript@5.7.3) typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -24886,6 +25028,8 @@ snapshots: eslint-visitor-keys@4.2.0: {} + eslint-visitor-keys@4.2.1: {} + eslint@9.22.0(jiti@2.5.1): dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.5.1)) @@ -24961,7 +25105,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.7 + '@types/estree': 1.0.8 esutils@2.0.3: {} @@ -25017,7 +25161,8 @@ snapshots: exit-hook@2.2.1: {} - exit@0.1.2: {} + exit@0.1.2: + optional: true expand-template@2.0.3: {} @@ -25027,6 +25172,8 @@ snapshots: expect-type@1.2.1: {} + expect-type@1.2.2: {} + expect@29.7.0: dependencies: '@jest/expect-utils': 29.7.0 @@ -25034,6 +25181,7 @@ snapshots: jest-matcher-utils: 29.7.0 jest-message-util: 29.7.0 jest-util: 29.7.0 + optional: true express-rate-limit@7.5.1(express@5.0.1): dependencies: @@ -25148,6 +25296,7 @@ snapshots: fb-watchman@2.0.2: dependencies: bser: 2.1.1 + optional: true fdir@6.4.2(picomatch@4.0.2): optionalDependencies: @@ -25157,6 +25306,10 @@ snapshots: optionalDependencies: picomatch: 4.0.2 + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + fetch-blob@3.2.0: dependencies: node-domexception: 1.0.0 @@ -25371,14 +25524,14 @@ snapshots: - encoding - supports-color - geist@1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + geist@1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: - next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) gel@2.0.1: dependencies: '@petamoriken/float16': 3.9.2 - debug: 4.4.1 + debug: 4.4.3 env-paths: 3.0.0 semver: 7.7.2 shell-quote: 1.8.3 @@ -25418,7 +25571,8 @@ snapshots: get-nonce@1.0.1: {} - get-package-type@0.1.0: {} + get-package-type@0.1.0: + optional: true get-proto@1.0.1: dependencies: @@ -25592,20 +25746,20 @@ snapshots: graphemer@1.4.0: {} - graphql-http@1.22.2(graphql@16.9.0): + graphql-http@1.22.2(graphql@16.8.1): dependencies: - graphql: 16.9.0 + graphql: 16.8.1 graphql-playground-html@1.6.30: dependencies: xss: 1.0.15 - graphql-scalars@1.22.2(graphql@16.9.0): + graphql-scalars@1.22.2(graphql@16.8.1): dependencies: - graphql: 16.9.0 + graphql: 16.8.1 tslib: 2.8.1 - graphql@16.9.0: {} + graphql@16.8.1: {} gtoken@7.1.0: dependencies: @@ -25778,6 +25932,7 @@ snapshots: dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 + optional: true imurmurhash@0.1.4: {} @@ -25935,7 +26090,8 @@ snapshots: dependencies: get-east-asian-width: 1.3.0 - is-generator-fn@2.1.0: {} + is-generator-fn@2.1.0: + optional: true is-generator-function@1.1.0: dependencies: @@ -26082,7 +26238,8 @@ snapshots: isomorphic.js@0.2.5: {} - istanbul-lib-coverage@3.2.2: {} + istanbul-lib-coverage@3.2.2: + optional: true istanbul-lib-instrument@5.2.1: dependencies: @@ -26093,6 +26250,7 @@ snapshots: semver: 6.3.1 transitivePeerDependencies: - supports-color + optional: true istanbul-lib-instrument@6.0.3: dependencies: @@ -26103,25 +26261,29 @@ snapshots: semver: 7.7.2 transitivePeerDependencies: - supports-color + optional: true istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 make-dir: 4.0.0 supports-color: 7.2.0 + optional: true istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.1 + debug: 4.4.3 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: - supports-color + optional: true istanbul-reports@3.1.7: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + optional: true iterator.prototype@1.1.5: dependencies: @@ -26147,6 +26309,7 @@ snapshots: execa: 5.1.1 jest-util: 29.7.0 p-limit: 3.1.0 + optional: true jest-circus@29.7.0(babel-plugin-macros@3.1.0): dependencies: @@ -26173,6 +26336,7 @@ snapshots: transitivePeerDependencies: - babel-plugin-macros - supports-color + optional: true jest-cli@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0): dependencies: @@ -26192,6 +26356,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true jest-config@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0): dependencies: @@ -26222,6 +26387,7 @@ snapshots: transitivePeerDependencies: - babel-plugin-macros - supports-color + optional: true jest-diff@29.7.0: dependencies: @@ -26229,10 +26395,12 @@ snapshots: diff-sequences: 29.6.3 jest-get-type: 29.6.3 pretty-format: 29.7.0 + optional: true jest-docblock@29.7.0: dependencies: detect-newline: 3.1.0 + optional: true jest-each@29.7.0: dependencies: @@ -26241,6 +26409,7 @@ snapshots: jest-get-type: 29.6.3 jest-util: 29.7.0 pretty-format: 29.7.0 + optional: true jest-environment-node@29.7.0: dependencies: @@ -26250,8 +26419,10 @@ snapshots: '@types/node': 22.15.30 jest-mock: 29.7.0 jest-util: 29.7.0 + optional: true - jest-get-type@29.6.3: {} + jest-get-type@29.6.3: + optional: true jest-haste-map@29.7.0: dependencies: @@ -26268,11 +26439,13 @@ snapshots: walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 + optional: true jest-leak-detector@29.7.0: dependencies: jest-get-type: 29.6.3 pretty-format: 29.7.0 + optional: true jest-matcher-utils@29.7.0: dependencies: @@ -26280,6 +26453,7 @@ snapshots: jest-diff: 29.7.0 jest-get-type: 29.6.3 pretty-format: 29.7.0 + optional: true jest-message-util@29.7.0: dependencies: @@ -26292,18 +26466,22 @@ snapshots: pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 + optional: true jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 '@types/node': 22.15.30 jest-util: 29.7.0 + optional: true jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): optionalDependencies: jest-resolve: 29.7.0 + optional: true - jest-regex-util@29.6.3: {} + jest-regex-util@29.6.3: + optional: true jest-regex-util@30.0.1: {} @@ -26313,6 +26491,7 @@ snapshots: jest-snapshot: 29.7.0 transitivePeerDependencies: - supports-color + optional: true jest-resolve@29.7.0: dependencies: @@ -26325,6 +26504,7 @@ snapshots: resolve: 1.22.8 resolve.exports: 2.0.2 slash: 3.0.0 + optional: true jest-runner@29.7.0: dependencies: @@ -26351,6 +26531,7 @@ snapshots: source-map-support: 0.5.13 transitivePeerDependencies: - supports-color + optional: true jest-runtime@29.7.0: dependencies: @@ -26378,14 +26559,15 @@ snapshots: strip-bom: 4.0.0 transitivePeerDependencies: - supports-color + optional: true jest-snapshot@29.7.0: dependencies: '@babel/core': 7.27.3 - '@babel/generator': 7.26.5 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.27.3) - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.27.3) - '@babel/types': 7.26.7 + '@babel/generator': 7.27.5 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.3) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.3) + '@babel/types': 7.27.3 '@jest/expect-utils': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 @@ -26403,6 +26585,7 @@ snapshots: semver: 7.7.2 transitivePeerDependencies: - supports-color + optional: true jest-util@29.7.0: dependencies: @@ -26412,6 +26595,7 @@ snapshots: ci-info: 3.9.0 graceful-fs: 4.2.11 picomatch: 2.3.1 + optional: true jest-validate@29.7.0: dependencies: @@ -26421,6 +26605,7 @@ snapshots: jest-get-type: 29.6.3 leven: 3.1.0 pretty-format: 29.7.0 + optional: true jest-watcher@29.7.0: dependencies: @@ -26432,6 +26617,7 @@ snapshots: emittery: 0.13.1 jest-util: 29.7.0 string-length: 4.0.2 + optional: true jest-worker@27.5.1: dependencies: @@ -26445,6 +26631,7 @@ snapshots: jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 + optional: true jest@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0): dependencies: @@ -26457,6 +26644,7 @@ snapshots: - babel-plugin-macros - supports-color - ts-node + optional: true jiti@1.21.6: {} @@ -26480,6 +26668,7 @@ snapshots: dependencies: argparse: 1.0.10 esprima: 4.0.1 + optional: true js-yaml@4.1.0: dependencies: @@ -26619,7 +26808,8 @@ snapshots: dependencies: language-subtag-registry: 0.3.23 - leven@3.1.0: {} + leven@3.1.0: + optional: true levn@0.4.1: dependencies: @@ -26815,6 +27005,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + magic-string@0.30.8: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -26835,17 +27029,18 @@ snapshots: makeerror@1.0.12: dependencies: tmpl: 1.0.5 + optional: true math-intrinsics@1.1.0: {} - mcp-handler@1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + mcp-handler@1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: '@modelcontextprotocol/sdk': 1.24.3(zod@3.25.76) chalk: 5.3.0 commander: 11.1.0 redis: 4.7.1 optionalDependencies: - next: 15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) md5@2.3.0: dependencies: @@ -27321,20 +27516,20 @@ snapshots: transitivePeerDependencies: - supports-color - next-sitemap@4.2.3(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + next-sitemap@4.2.3(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: '@corex/deepmerge': 4.0.43 '@next/env': 13.5.11 fast-glob: 3.3.2 minimist: 1.2.8 - next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes@0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: react: 19.2.1 react-dom: 19.2.1(react@19.2.1) - next@15.4.10(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.10(@babel/core@7.27.3)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: '@next/env': 15.4.10 '@swc/helpers': 0.5.15 @@ -27342,7 +27537,7 @@ snapshots: postcss: 8.4.31 react: 19.2.1 react-dom: 19.2.1(react@19.2.1) - styled-jsx: 5.1.6(@babel/core@7.27.3)(babel-plugin-macros@3.1.0)(react@19.2.1) + styled-jsx: 5.1.6(@babel/core@7.27.3)(react@19.2.1) optionalDependencies: '@next/swc-darwin-arm64': 15.4.8 '@next/swc-darwin-x64': 15.4.8 @@ -27361,7 +27556,7 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: '@next/env': 15.4.10 '@swc/helpers': 0.5.15 @@ -27369,7 +27564,7 @@ snapshots: postcss: 8.4.31 react: 19.2.1 react-dom: 19.2.1(react@19.2.1) - styled-jsx: 5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.2.1) + styled-jsx: 5.1.6(@babel/core@7.27.4)(react@19.2.1) optionalDependencies: '@next/swc-darwin-arm64': 15.4.8 '@next/swc-darwin-x64': 15.4.8 @@ -27387,7 +27582,7 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: '@next/env': 15.4.10 '@swc/helpers': 0.5.15 @@ -27395,7 +27590,7 @@ snapshots: postcss: 8.4.31 react: 19.2.1 react-dom: 19.2.1(react@19.2.1) - styled-jsx: 5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.2.1) + styled-jsx: 5.1.6(react@19.2.1) optionalDependencies: '@next/swc-darwin-arm64': 15.4.8 '@next/swc-darwin-x64': 15.4.8 @@ -27414,7 +27609,33 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): + dependencies: + '@next/env': 15.4.10 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001720 + postcss: 8.4.31 + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + styled-jsx: 5.1.6(react@19.2.1) + optionalDependencies: + '@next/swc-darwin-arm64': 15.4.8 + '@next/swc-darwin-x64': 15.4.8 + '@next/swc-linux-arm64-gnu': 15.4.8 + '@next/swc-linux-arm64-musl': 15.4.8 + '@next/swc-linux-x64-gnu': 15.4.8 + '@next/swc-linux-x64-musl': 15.4.8 + '@next/swc-win32-arm64-msvc': 15.4.8 + '@next/swc-win32-x64-msvc': 15.4.8 + '@opentelemetry/api': 1.9.0 + '@playwright/test': 1.56.1 + sass: 1.77.4 + sharp: 0.34.3 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: '@next/env': 15.5.4 '@swc/helpers': 0.5.15 @@ -27422,7 +27643,7 @@ snapshots: postcss: 8.4.31 react: 19.2.1 react-dom: 19.2.1(react@19.2.1) - styled-jsx: 5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.2.1) + styled-jsx: 5.1.6(react@19.2.1) optionalDependencies: '@next/swc-darwin-arm64': 15.5.4 '@next/swc-darwin-x64': 15.5.4 @@ -27462,7 +27683,8 @@ snapshots: node-gyp-build@4.8.2: {} - node-int64@0.4.0: {} + node-int64@0.4.0: + optional: true node-releases@2.0.18: {} @@ -27588,6 +27810,8 @@ snapshots: obuf@1.1.2: {} + obug@2.1.1: {} + ofetch@1.4.1: dependencies: destr: 2.0.3 @@ -27835,6 +28059,8 @@ snapshots: picomatch@4.0.2: {} + picomatch@4.0.3: {} + pidtree@0.6.0: {} pify@2.3.0: {} @@ -28013,6 +28239,7 @@ snapshots: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 react-is: 18.3.1 + optional: true prism-react-renderer@2.4.1(react@19.2.1): dependencies: @@ -28141,13 +28368,13 @@ snapshots: react-is@18.3.1: {} - react-redux@9.2.0(@types/react@19.2.1)(react@19.2.1)(redux@5.0.1): + react-redux@9.2.0(@types/react@19.1.12)(react@19.2.1)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 react: 19.2.1 use-sync-external-store: 1.5.0(react@19.2.1) optionalDependencies: - '@types/react': 19.2.1 + '@types/react': 19.1.12 redux: 5.0.1 react-refresh@0.17.0: {} @@ -28265,9 +28492,9 @@ snapshots: real-require@0.2.0: {} - recharts@3.2.1(@types/react@19.2.1)(react-dom@19.2.1(react@19.2.1))(react-is@18.3.1)(react@19.2.1)(redux@5.0.1): + recharts@3.2.1(@types/react@19.1.12)(react-dom@19.2.1(react@19.2.1))(react-is@18.3.1)(react@19.2.1)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.2.1)(react@19.2.1)(redux@5.0.1))(react@19.2.1) + '@reduxjs/toolkit': 2.9.0(react-redux@9.2.0(@types/react@19.1.12)(react@19.2.1)(redux@5.0.1))(react@19.2.1) clsx: 2.1.1 decimal.js-light: 2.5.1 es-toolkit: 1.39.10 @@ -28276,7 +28503,7 @@ snapshots: react: 19.2.1 react-dom: 19.2.1(react@19.2.1) react-is: 18.3.1 - react-redux: 9.2.0(@types/react@19.2.1)(react@19.2.1)(redux@5.0.1) + react-redux: 9.2.0(@types/react@19.1.12)(react@19.2.1)(redux@5.0.1) reselect: 5.1.1 tiny-invariant: 1.3.3 use-sync-external-store: 1.5.0(react@19.2.1) @@ -28405,6 +28632,7 @@ snapshots: resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 + optional: true resolve-dir@1.0.1: dependencies: @@ -28413,11 +28641,13 @@ snapshots: resolve-from@4.0.0: {} - resolve-from@5.0.0: {} + resolve-from@5.0.0: + optional: true resolve-pkg-maps@1.0.0: {} - resolve.exports@2.0.2: {} + resolve.exports@2.0.2: + optional: true resolve@1.22.8: dependencies: @@ -28480,32 +28710,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - rollup@4.43.0: - dependencies: - '@types/estree': 1.0.7 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.43.0 - '@rollup/rollup-android-arm64': 4.43.0 - '@rollup/rollup-darwin-arm64': 4.43.0 - '@rollup/rollup-darwin-x64': 4.43.0 - '@rollup/rollup-freebsd-arm64': 4.43.0 - '@rollup/rollup-freebsd-x64': 4.43.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.43.0 - '@rollup/rollup-linux-arm-musleabihf': 4.43.0 - '@rollup/rollup-linux-arm64-gnu': 4.43.0 - '@rollup/rollup-linux-arm64-musl': 4.43.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.43.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.43.0 - '@rollup/rollup-linux-riscv64-gnu': 4.43.0 - '@rollup/rollup-linux-riscv64-musl': 4.43.0 - '@rollup/rollup-linux-s390x-gnu': 4.43.0 - '@rollup/rollup-linux-x64-gnu': 4.43.0 - '@rollup/rollup-linux-x64-musl': 4.43.0 - '@rollup/rollup-win32-arm64-msvc': 4.43.0 - '@rollup/rollup-win32-ia32-msvc': 4.43.0 - '@rollup/rollup-win32-x64-msvc': 4.43.0 - fsevents: 2.3.3 - rollup@4.52.3: dependencies: '@types/estree': 1.0.8 @@ -29072,6 +29276,7 @@ snapshots: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + optional: true source-map-support@0.5.21: dependencies: @@ -29118,7 +29323,8 @@ snapshots: split2@4.2.0: {} - sprintf-js@1.0.3: {} + sprintf-js@1.0.3: + optional: true sprintf-js@1.1.3: optional: true @@ -29132,6 +29338,7 @@ snapshots: stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 + optional: true stackback@0.0.2: {} @@ -29145,6 +29352,8 @@ snapshots: statuses@2.0.1: {} + std-env@3.10.0: {} + std-env@3.7.0: {} std-env@3.9.0: {} @@ -29191,6 +29400,7 @@ snapshots: dependencies: char-regex: 1.0.2 strip-ansi: 6.0.1 + optional: true string-ts@2.2.1: {} @@ -29300,7 +29510,8 @@ snapshots: strip-bom@3.0.0: {} - strip-bom@4.0.0: {} + strip-bom@4.0.0: + optional: true strip-dirs@3.0.0: dependencies: @@ -29349,21 +29560,24 @@ snapshots: stubs@3.0.0: {} - styled-jsx@5.1.6(@babel/core@7.27.3)(babel-plugin-macros@3.1.0)(react@19.2.1): + styled-jsx@5.1.6(@babel/core@7.27.3)(react@19.2.1): dependencies: client-only: 0.0.1 react: 19.2.1 optionalDependencies: '@babel/core': 7.27.3 - babel-plugin-macros: 3.1.0 - styled-jsx@5.1.6(@babel/core@7.27.4)(babel-plugin-macros@3.1.0)(react@19.2.1): + styled-jsx@5.1.6(@babel/core@7.27.4)(react@19.2.1): dependencies: client-only: 0.0.1 react: 19.2.1 optionalDependencies: '@babel/core': 7.27.4 - babel-plugin-macros: 3.1.0 + + styled-jsx@5.1.6(react@19.2.1): + dependencies: + client-only: 0.0.1 + react: 19.2.1 stylis@4.2.0: {} @@ -29552,6 +29766,7 @@ snapshots: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 minimatch: 3.1.2 + optional: true text-decoder@1.2.1: {} @@ -29584,6 +29799,8 @@ snapshots: tinyexec@0.3.2: {} + tinyexec@1.0.2: {} + tinyglobby@0.2.10: dependencies: fdir: 6.4.2(picomatch@4.0.2) @@ -29594,10 +29811,17 @@ snapshots: fdir: 6.4.6(picomatch@4.0.2) picomatch: 4.0.2 + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + tinypool@1.1.0: {} tinyrainbow@2.0.0: {} + tinyrainbow@3.0.3: {} + tinyspy@4.0.3: {} tldts-core@6.1.86: {} @@ -29606,7 +29830,8 @@ snapshots: dependencies: tldts-core: 6.1.86 - tmpl@1.0.5: {} + tmpl@1.0.5: + optional: true to-no-case@1.0.2: {} @@ -29659,6 +29884,10 @@ snapshots: dependencies: typescript: 5.7.3 + ts-api-utils@2.1.0(typescript@5.7.3): + dependencies: + typescript: 5.7.3 + ts-essentials@10.0.3(typescript@5.7.3): optionalDependencies: typescript: 5.7.3 @@ -29749,7 +29978,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-detect@4.0.8: {} + type-detect@4.0.8: + optional: true type-fest@0.16.0: {} @@ -29976,7 +30206,7 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - uploadthing@7.3.0(express@5.0.1)(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(tailwindcss@4.1.13): + uploadthing@7.3.0(express@5.0.1)(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(tailwindcss@4.1.13): dependencies: '@effect/platform': 0.69.8(effect@3.10.3) '@uploadthing/mime-types': 0.3.2 @@ -29984,7 +30214,7 @@ snapshots: effect: 3.10.3 optionalDependencies: express: 5.0.1 - next: 15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) tailwindcss: 4.1.13 uri-js@4.4.1: @@ -30050,6 +30280,7 @@ snapshots: '@jridgewell/trace-mapping': 0.3.25 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + optional: true validate-npm-package-license@3.0.4: dependencies: @@ -30150,14 +30381,33 @@ snapshots: - supports-color - typescript + vite@6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.19.2)(yaml@2.8.1): + dependencies: + esbuild: 0.25.5 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.5 + rollup: 4.52.3 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.15.30 + fsevents: 2.3.3 + jiti: 2.5.1 + lightningcss: 1.30.1 + sass: 1.77.4 + sass-embedded: 1.80.6 + terser: 5.36.0 + tsx: 4.19.2 + yaml: 2.8.1 + vite@6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.25.5 - fdir: 6.4.6(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 postcss: 8.5.5 - rollup: 4.43.0 - tinyglobby: 0.2.14 + rollup: 4.52.3 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.15.30 fsevents: 2.3.3 @@ -30172,11 +30422,11 @@ snapshots: vite@6.3.5(@types/node@22.5.4)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1): dependencies: esbuild: 0.25.5 - fdir: 6.4.6(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 postcss: 8.5.5 - rollup: 4.43.0 - tinyglobby: 0.2.14 + rollup: 4.52.3 + tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.5.4 fsevents: 2.3.3 @@ -30274,6 +30524,84 @@ snapshots: - tsx - yaml + vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.15.30)(jiti@2.5.1)(jsdom@26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.19.2)(yaml@2.8.1): + dependencies: + '@vitest/expect': 4.0.15 + '@vitest/mocker': 4.0.15(vite@6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.19.2)(yaml@2.8.1)) + '@vitest/pretty-format': 4.0.15 + '@vitest/runner': 4.0.15 + '@vitest/snapshot': 4.0.15 + '@vitest/spy': 4.0.15 + '@vitest/utils': 4.0.15 + es-module-lexer: 1.7.0 + expect-type: 1.2.2 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.19.2)(yaml@2.8.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@types/node': 22.15.30 + jsdom: 26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5) + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + + vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.15.30)(jiti@2.5.1)(jsdom@26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1): + dependencies: + '@vitest/expect': 4.0.15 + '@vitest/mocker': 4.0.15(vite@6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1)) + '@vitest/pretty-format': 4.0.15 + '@vitest/runner': 4.0.15 + '@vitest/snapshot': 4.0.15 + '@vitest/spy': 4.0.15 + '@vitest/utils': 4.0.15 + es-module-lexer: 1.7.0 + expect-type: 1.2.2 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 6.3.5(@types/node@22.15.30)(jiti@2.5.1)(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.0 + '@types/node': 22.15.30 + jsdom: 26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5) + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + vue@3.5.12(typescript@5.7.3): dependencies: '@vue/compiler-dom': 3.5.12 @@ -30291,6 +30619,7 @@ snapshots: walker@1.0.8: dependencies: makeerror: 1.0.12 + optional: true watchpack@2.4.2: dependencies: @@ -30305,7 +30634,7 @@ snapshots: webidl-conversions@7.0.0: {} - webpack-bundle-analyzer@4.10.1(bufferutil@4.0.8): + webpack-bundle-analyzer@4.10.1(bufferutil@4.0.8)(utf-8-validate@6.0.5): dependencies: '@discoveryjs/json-ext': 0.5.7 acorn: 8.12.1 @@ -30319,7 +30648,7 @@ snapshots: opener: 1.5.2 picocolors: 1.1.1 sirv: 2.0.4 - ws: 7.5.10(bufferutil@4.0.8) + ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.5) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -30503,10 +30832,12 @@ snapshots: dependencies: imurmurhash: 0.1.4 signal-exit: 3.0.7 + optional: true - ws@7.5.10(bufferutil@4.0.8): + ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.5): optionalDependencies: bufferutil: 4.0.8 + utf-8-validate: 6.0.5 ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.5): optionalDependencies: @@ -30542,7 +30873,8 @@ snapshots: yargs-parser@20.2.9: {} - yargs-parser@21.1.1: {} + yargs-parser@21.1.1: + optional: true yargs-parser@22.0.0: {} @@ -30565,6 +30897,7 @@ snapshots: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 + optional: true yargs@18.0.0: dependencies: diff --git a/test/_community/int.spec.ts b/test/_community/int.spec.ts index 52676c05872..f6217a12522 100644 --- a/test/_community/int.spec.ts +++ b/test/_community/int.spec.ts @@ -2,6 +2,7 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/access-control/int.spec.ts b/test/access-control/int.spec.ts index 71f4b6ae106..1d343d4208d 100644 --- a/test/access-control/int.spec.ts +++ b/test/access-control/int.spec.ts @@ -12,6 +12,7 @@ import path from 'path' import { createLocalReq, Forbidden } from 'payload' import { getEntityPermissions } from 'payload/internal' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, beforeEach, describe, expect, it, vitest } from 'vitest' import type { FullyRestricted, Post } from './payload-types.js' @@ -698,7 +699,7 @@ describe('Access Control', () => { it('should not allow reset password if forgotPassword expiration token is expired', async () => { // Mock Date.now() to simulate the forgotPassword call happening 1 hour ago (default is 1 hour) const originalDateNow = Date.now - const mockDateNow = jest.spyOn(Date, 'now').mockImplementation(() => { + const mockDateNow = vitest.spyOn(Date, 'now').mockImplementation(() => { // Move the current time back by 1 hour return originalDateNow() - 60 * 60 * 1000 }) diff --git a/test/access-control/postgres-logs.int.spec.ts b/test/access-control/postgres-logs.int.spec.ts index 5684f9c8a43..8060d6af059 100644 --- a/test/access-control/postgres-logs.int.spec.ts +++ b/test/access-control/postgres-logs.int.spec.ts @@ -1,11 +1,11 @@ import type { CollectionPermission, Payload, PayloadRequest } from 'payload' -/* eslint-disable jest/require-top-level-describe */ import assert from 'assert' import path from 'path' import { createLocalReq } from 'payload' import { getEntityPermissions } from 'payload/internal' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it, vitest } from 'vitest' import { initPayloadInt } from '../helpers/initPayloadInt.js' import { whereCacheSameSlug, whereCacheUniqueSlug } from './shared.js' @@ -64,7 +64,7 @@ describePostgres('Access Control - postgres logs', () => { }, }) - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) // Get permissions - all operations return same where query const permissions = await getEntityPermissions({ @@ -104,7 +104,7 @@ describePostgres('Access Control - postgres logs', () => { }, }) - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) // Get permissions - all operations return same where query const permissions = await getEntityPermissions({ @@ -149,7 +149,7 @@ describePostgres('Access Control - postgres logs', () => { }, }) - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) // Get permissions - each operation returns unique where query const permissions = await getEntityPermissions({ @@ -192,7 +192,7 @@ describePostgres('Access Control - postgres logs', () => { }, }) - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) // Get permissions - each operation returns unique where query const permissions = await getEntityPermissions({ @@ -272,7 +272,7 @@ describePostgres('Access Control - postgres logs', () => { }, }) - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) // Get permissions - each operation returns unique where query const permissions = await getEntityPermissions({ diff --git a/test/admin-root/int.spec.ts b/test/admin-root/int.spec.ts index 36a0bc5399e..481ef493953 100644 --- a/test/admin-root/int.spec.ts +++ b/test/admin-root/int.spec.ts @@ -2,6 +2,7 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/array-update/int.spec.ts b/test/array-update/int.spec.ts index 2d42d48f23d..92fece14406 100644 --- a/test/array-update/int.spec.ts +++ b/test/array-update/int.spec.ts @@ -1,4 +1,5 @@ import type { Payload } from 'payload' +import { describe, beforeAll, afterAll, it, expect } from 'vitest' import path from 'path' import { fileURLToPath } from 'url' diff --git a/test/auth/custom-strategy/int.spec.ts b/test/auth/custom-strategy/int.spec.ts index 01f8b4c6a4b..cf5ca51946a 100644 --- a/test/auth/custom-strategy/int.spec.ts +++ b/test/auth/custom-strategy/int.spec.ts @@ -2,6 +2,7 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../../helpers/NextRESTClient.js' diff --git a/test/auth/forgot-password-localized/int.spec.ts b/test/auth/forgot-password-localized/int.spec.ts index e38f3897b57..d061b36ab21 100644 --- a/test/auth/forgot-password-localized/int.spec.ts +++ b/test/auth/forgot-password-localized/int.spec.ts @@ -2,6 +2,7 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../../helpers/NextRESTClient.js' diff --git a/test/auth/int.spec.ts b/test/auth/int.spec.ts index 03e894fdbcc..e722a47dd48 100644 --- a/test/auth/int.spec.ts +++ b/test/auth/int.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable jest/no-conditional-in-test */ import type { BasePayload, EmailFieldValidation, @@ -14,6 +13,7 @@ import path from 'path' import { email as emailValidation } from 'payload/shared' import { fileURLToPath } from 'url' import { v4 as uuid } from 'uuid' +import { afterAll, beforeAll, beforeEach, describe, expect, it, vitest } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { ApiKey } from './payload-types.js' @@ -1149,7 +1149,7 @@ describe('Auth', () => { it('should not allow reset password if forgotPassword expiration token is expired', async () => { // Mock Date.now() to simulate the forgotPassword call happening 6 minutes ago (current expiration is set to 5 minutes) const originalDateNow = Date.now - const mockDateNow = jest.spyOn(Date, 'now').mockImplementation(() => { + const mockDateNow = vitest.spyOn(Date, 'now').mockImplementation(() => { // Move the current time back by 6 minutes (360,000 ms) return originalDateNow() - 6 * 60 * 1000 }) @@ -1313,7 +1313,7 @@ describe('Auth', () => { }) describe('Email - format validation', () => { - const mockT = jest.fn((key) => key) // Mocks translation function + const mockT = vitest.fn((key) => key) // Mocks translation function const mockContext: Parameters[1] = { // @ts-expect-error: Mocking context for email validation diff --git a/test/auth/removed-token/int.spec.ts b/test/auth/removed-token/int.spec.ts index 4260bc9b3cb..262357f593b 100644 --- a/test/auth/removed-token/int.spec.ts +++ b/test/auth/removed-token/int.spec.ts @@ -2,6 +2,7 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../../helpers/NextRESTClient.js' diff --git a/test/collections-graphql/int.spec.ts b/test/collections-graphql/int.spec.ts index b0c9e511f7b..9deef9211dc 100644 --- a/test/collections-graphql/int.spec.ts +++ b/test/collections-graphql/int.spec.ts @@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url' import path from 'path' import { getFileByPath, mapAsync } from 'payload' import { wait } from 'payload/shared' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { Post } from './payload-types.js' diff --git a/test/collections-rest/int.spec.ts b/test/collections-rest/int.spec.ts index 0f1fe04d4d4..0c30e84c6e1 100644 --- a/test/collections-rest/int.spec.ts +++ b/test/collections-rest/int.spec.ts @@ -5,6 +5,7 @@ import { serialize } from 'object-to-formdata' import path from 'path' import { APIError, NotFound } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { Relation } from './config.js' diff --git a/test/config/int.spec.ts b/test/config/int.spec.ts index 9f8c102108c..87f07e7d0af 100644 --- a/test/config/int.spec.ts +++ b/test/config/int.spec.ts @@ -3,6 +3,7 @@ import { existsSync, readFileSync, rmSync } from 'fs' import path from 'path' import { type BlocksField, getPayload, type Payload } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/create-payload-app/int.spec.ts b/test/create-payload-app/int.spec.ts index 3a2053efb20..00edd02b823 100644 --- a/test/create-payload-app/int.spec.ts +++ b/test/create-payload-app/int.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable jest/no-conditional-in-test */ import type { CompilerOptions } from 'typescript' import * as CommentJson from 'comment-json' @@ -10,6 +9,7 @@ import path from 'path' import shelljs from 'shelljs' import tempy from 'tempy' import { promisify } from 'util' +import { afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest' const readFile = promisify(fs.readFile) const writeFile = promisify(fs.writeFile) @@ -64,7 +64,7 @@ describe('create-payload-app', () => { let userTsConfigContent = await readFile(tsConfigPath, { encoding: 'utf8' }) userTsConfigContent = userTsConfigContent.replace('""@/*""', '"@/*"') await writeFile(tsConfigPath, userTsConfigContent, { encoding: 'utf8' }) - }) + }, 90000) afterEach(() => { if (fs.existsSync(projectDir)) { @@ -129,7 +129,7 @@ describe('create-payload-app', () => { } // Check that `@payload-config` path is added to tsconfig - expect(userTsConfig.compilerOptions?.paths?.['@payload-config']).toStrictEqual([ + expect(userTsConfig.compilerOptions?.paths?.['@payload-config']).toEqual([ `./${result.isSrcDir ? 'src/' : ''}payload.config.ts`, ]) diff --git a/test/custom-graphql/int.spec.ts b/test/custom-graphql/int.spec.ts index 879e7c5ce1e..1873f2bb33a 100644 --- a/test/custom-graphql/int.spec.ts +++ b/test/custom-graphql/int.spec.ts @@ -2,6 +2,7 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/database/int.spec.ts b/test/database/int.spec.ts index b050fbb345a..678c0540601 100644 --- a/test/database/int.spec.ts +++ b/test/database/int.spec.ts @@ -1,5 +1,6 @@ import type { MongooseAdapter } from '@payloadcms/db-mongodb' import type { PostgresAdapter } from '@payloadcms/db-postgres' +import type { Table } from 'drizzle-orm' import type { NextRESTClient } from 'helpers/NextRESTClient.js' import type { DataFromCollectionSlug, @@ -28,13 +29,14 @@ import { } from 'payload' import { assert } from 'ts-essentials' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { Global2, Post } from './payload-types.js' import { sanitizeQueryValue } from '../../packages/db-mongodb/src/queries/sanitizeQueryValue.js' import { devUser } from '../credentials.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' -import { isMongoose } from '../helpers/isMongoose.js' +import { isMongoose, mongooseList } from '../helpers/isMongoose.js' import removeFiles from '../helpers/removeFiles.js' import { seed } from './seed.js' import { errorOnUnnamedFieldsSlug, fieldsPersistanceSlug, postsSlug } from './shared.js' @@ -599,12 +601,10 @@ describe('database', () => { expect(updatedDocWithTimestamps.updatedAt).toBeUndefined() } - // eslint-disable-next-line jest/expect-expect it('ensure timestamps are not created in update or create when timestamps are disabled', async () => { await noTimestampsTestLocalAPI() }) - // eslint-disable-next-line jest/expect-expect it('ensure timestamps are not created in db adapter update or create when timestamps are disabled', async () => { await noTimestampsTestDB(true) }) @@ -772,7 +772,6 @@ describe('database', () => { ].map((title) => ({ title })) for (const { title } of titles) { - // eslint-disable-next-line jest/no-conditional-in-test const docsCount = Math.random() > 0.5 ? 3 : Math.random() > 0.5 ? 2 : 1 for (let i = 0; i < docsCount; i++) { await payload.create({ collection: 'posts', data: { title } }) @@ -840,7 +839,6 @@ describe('database', () => { } for (const { category } of categoriesIDS) { - // eslint-disable-next-line jest/no-conditional-in-test const docsCount = Math.random() > 0.5 ? 3 : Math.random() > 0.5 ? 2 : 1 for (let i = 0; i < docsCount; i++) { await payload.create({ collection: 'posts', data: { category, title: randomUUID() } }) @@ -938,7 +936,6 @@ describe('database', () => { } // Non-consistent sorting by ID - // eslint-disable-next-line jest/no-conditional-in-test if (process.env.PAYLOAD_DATABASE?.includes('uuid')) { return } @@ -1521,18 +1518,11 @@ describe('database', () => { }) it('should run migrate', async () => { - let error - try { - await payload.db.migrate() - } catch (e) { - console.error(e) - error = e - } + await payload.db.migrate() const { docs } = await payload.find({ collection: 'payload-migrations', }) const migration = docs[0] - expect(error).toBeUndefined() expect(migration?.name).toContain('_test') expect(migration?.batch).toStrictEqual(1) }) @@ -1560,7 +1550,6 @@ describe('database', () => { it('should run migrate:down', async () => { // known drizzle issue: https://github.com/payloadcms/payload/issues/4597 - // eslint-disable-next-line jest/no-conditional-in-test if (!isMongoose(payload)) { return } @@ -1599,7 +1588,6 @@ describe('database', () => { it('should run migrate:refresh', async () => { // known drizzle issue: https://github.com/payloadcms/payload/issues/4597 - // eslint-disable-next-line jest/no-conditional-in-test if (!isMongoose(payload)) { return } @@ -1621,7 +1609,6 @@ describe('database', () => { it('should run migrate:reset', async () => { // known drizzle issue: https://github.com/payloadcms/payload/issues/4597 - // eslint-disable-next-line jest/no-conditional-in-test if (!isMongoose(payload)) { return } @@ -1642,7 +1629,6 @@ describe('database', () => { describe('predefined migrations', () => { it('mongoose - should execute migrateVersionsV1_V2', async () => { - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name !== 'mongoose') { return } @@ -1663,7 +1649,6 @@ describe('database', () => { }) it('mongoose - should execute migrateRelationshipsV2_V3', async () => { - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name !== 'mongoose') { return } @@ -2779,8 +2764,15 @@ describe('database', () => { }) }) - describe('Schema generation', () => { - if (process.env.PAYLOAD_DATABASE.includes('postgres')) { + const describeSQL = mongooseList.includes(process.env.PAYLOAD_DATABASE!) + ? describe.skip + : describe + + describeSQL('Schema generation', () => { + if ( + process.env.PAYLOAD_DATABASE.includes('postgres') || + process.env.PAYLOAD_DATABASE === 'supabase' + ) { it('should generate Drizzle Postgres schema', async () => { const generatedAdapterName = process.env.PAYLOAD_DATABASE @@ -2841,7 +2833,6 @@ describe('database', () => { // TODO: this test is currently not working, come back to fix in a separate PR, issue: 12907 it.skip('should add tables with hooks', async () => { - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name === 'mongoose') { return } @@ -2849,9 +2840,7 @@ describe('database', () => { let added_table_before: Table let added_table_after: Table - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name.includes('postgres')) { - // eslint-disable-next-line jest/no-conditional-in-test const t = (payload.db.pgSchema?.table ?? drizzlePg.pgTable) as typeof drizzlePg.pgTable added_table_before = t('added_table_before', { id: drizzlePg.serial('id').primaryKey(), @@ -2864,7 +2853,6 @@ describe('database', () => { }) } - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name.includes('sqlite')) { added_table_before = drizzleSqlite.sqliteTable('added_table_before', { id: drizzleSqlite.integer('id').primaryKey(), @@ -2931,7 +2919,6 @@ describe('database', () => { }) it('should extend the existing table with extra column and modify the existing column with enforcing DB level length', async () => { - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name === 'mongoose') { return } @@ -2943,11 +2930,9 @@ describe('database', () => { extendTable({ columns: { // SQLite doesn't have DB length enforcement - // eslint-disable-next-line jest/no-conditional-in-test ...(payload.db.name === 'postgres' && { city: drizzlePg.varchar('city', { length: 10 }), }), - // eslint-disable-next-line jest/no-conditional-in-test extraColumn: isSQLite ? drizzleSqlite.integer('extra_column') : drizzlePg.integer('extra_column'), @@ -2973,7 +2958,6 @@ describe('database', () => { }, }) - // eslint-disable-next-line jest/no-conditional-in-test const tableName = payload.db.schemaName ? `"${payload.db.schemaName}"."places"` : 'places' await payload.db.execute({ @@ -2989,7 +2973,6 @@ describe('database', () => { expect(res_with_extra_col.rows[0].extra_column).toBe(10) // SQLite doesn't have DB length enforcement - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name === 'postgres') { await expect( payload.db.execute({ @@ -3001,7 +2984,6 @@ describe('database', () => { }) it('should extend the existing table with composite unique and throw ValidationError on it', async () => { - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name === 'mongoose') { return } @@ -3012,7 +2994,6 @@ describe('database', () => { ({ extendTable, schema }) => { extendTable({ extraConfig: (t) => ({ - // eslint-disable-next-line jest/no-conditional-in-test uniqueOnCityAndCountry: (isSQLite ? drizzleSqlite : drizzlePg) .unique() .on(t.city, t.country), @@ -3493,11 +3474,9 @@ describe('database', () => { it('should automatically add hasMany: true to a virtual field that references a hasMany relationship', () => { const field = payload.collections['virtual-relations'].config.fields.find( - // eslint-disable-next-line jest/no-conditional-in-test (each) => 'name' in each && each.name === 'postsTitles', )! - // eslint-disable-next-line jest/no-conditional-in-test expect('hasMany' in field && field.hasMany).toBe(true) }) @@ -3746,7 +3725,6 @@ describe('database', () => { }) it('mongodb additional keys stripping', async () => { - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name !== 'mongoose') { return } @@ -3991,7 +3969,6 @@ describe('database', () => { const res = await payload.find({ collection: 'categories', draft: true, - // eslint-disable-next-line jest/no-conditional-in-test where: { id: { like: typeof category.id === 'number' ? `${category.id}` : category.id } }, }) expect(res.docs).toHaveLength(1) @@ -5134,7 +5111,6 @@ describe('database', () => { it('should ignore blocks that exist in the db but not in the config', async () => { // not possible w/ SQL anyway - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name !== 'mongoose') { return } @@ -5180,7 +5156,6 @@ describe('database', () => { }) it('should CRUD with blocks as JSON in SQL adapters', async () => { - // eslint-disable-next-line jest/no-conditional-in-test if (!('drizzle' in payload.db)) { return } @@ -5228,7 +5203,6 @@ describe('database', () => { }) it('ensure mongodb query sanitization does not duplicate IDs', () => { - // eslint-disable-next-line jest/no-conditional-in-test if (!isMongoose(payload)) { return } diff --git a/test/database/postgres-logs.int.spec.ts b/test/database/postgres-logs.int.spec.ts index a72610fc39d..2376ca31003 100644 --- a/test/database/postgres-logs.int.spec.ts +++ b/test/database/postgres-logs.int.spec.ts @@ -1,10 +1,10 @@ import type { Payload } from 'payload' -/* eslint-disable jest/require-top-level-describe */ import assert from 'assert' import mongoose from 'mongoose' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it, vitest } from 'vitest' import type { Post } from './payload-types.js' @@ -46,7 +46,7 @@ describePostgres('database - postgres logs', () => { }) // Count every console log - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) const result: any = await payload.db.updateOne({ collection: 'simple', @@ -74,7 +74,7 @@ describePostgres('database - postgres logs', () => { }) // Count every console log - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) const result: any = await payload.db.updateOne({ collection: 'posts', @@ -115,7 +115,7 @@ describePostgres('database - postgres logs', () => { }, }) // Count every console log - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) await payload.db.deleteMany({ collection: 'posts', @@ -155,7 +155,7 @@ describePostgres('database - postgres logs', () => { }, }) // Count every console log - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) await payload.db.deleteMany({ collection: 'posts', @@ -187,7 +187,7 @@ describePostgres('database - postgres logs', () => { title: 'post', }, }) - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) await payload.db.updateOne({ data: { diff --git a/test/database/postgres-relationships-v2-v3-migration/int.spec.ts b/test/database/postgres-relationships-v2-v3-migration/int.spec.ts index f769cc0d0c3..8ee94e10f16 100644 --- a/test/database/postgres-relationships-v2-v3-migration/int.spec.ts +++ b/test/database/postgres-relationships-v2-v3-migration/int.spec.ts @@ -1,15 +1,14 @@ -/* eslint-disable jest/require-top-level-describe */ import path from 'path' import { buildConfig, getPayload } from 'payload' import { fileURLToPath } from 'url' +import { describe, expect, it } from 'vitest' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) -const describe = - process.env.PAYLOAD_DATABASE === 'postgres' ? global.describe : global.describe.skip +const describeToUse = process.env.PAYLOAD_DATABASE === 'postgres' ? describe : describe.skip -describe('Postgres relationships v2-v3 migration', () => { +describeToUse('Postgres relationships v2-v3 migration', () => { it('should execute relationships v2-v3 migration', async () => { const { databaseAdapter } = await import(path.resolve(dirname, '../../databaseAdapter.js')) diff --git a/test/database/postgres-vector.int.spec.ts b/test/database/postgres-vector.int.spec.ts index 58a10743fd3..32668271f22 100644 --- a/test/database/postgres-vector.int.spec.ts +++ b/test/database/postgres-vector.int.spec.ts @@ -1,6 +1,3 @@ -/* eslint-disable jest/no-conditional-in-test */ -/* eslint-disable jest/expect-expect */ -/* eslint-disable jest/require-top-level-describe */ import type { PostgresAdapter } from '@payloadcms/db-postgres' import type { PostgresDB } from '@payloadcms/drizzle' @@ -8,6 +5,7 @@ import { cosineDistance, desc, gt, jaccardDistance, l2Distance, lt, sql } from ' import path from 'path' import { BasePayload, buildConfig, type DatabaseAdapterObj } from 'payload' import { fileURLToPath } from 'url' +import { describe, expect, it } from 'vitest' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) diff --git a/test/database/sqlite-bound-parameters-limit.int.spec.ts b/test/database/sqlite-bound-parameters-limit.int.spec.ts index 223adb0013e..ef62b2c46d5 100644 --- a/test/database/sqlite-bound-parameters-limit.int.spec.ts +++ b/test/database/sqlite-bound-parameters-limit.int.spec.ts @@ -1,8 +1,8 @@ import type { Payload } from 'payload' -/* eslint-disable jest/require-top-level-describe */ import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import { initPayloadInt } from '../helpers/initPayloadInt.js' @@ -30,7 +30,6 @@ describeSqlite('database - sqlite bound parameters limit', () => { const res = await defaultExecute(...args) const [{ args: boundParameters }] = args as [{ args: any[] }] - // eslint-disable-next-line jest/no-conditional-in-test if (boundParameters.length > 100) { throw new Error('Exceeded limit of bound parameters!') } diff --git a/test/database/up-down-migration/int.spec.ts b/test/database/up-down-migration/int.spec.ts index 472a952cf35..a0fd3bd5830 100644 --- a/test/database/up-down-migration/int.spec.ts +++ b/test/database/up-down-migration/int.spec.ts @@ -1,14 +1,13 @@ -/* eslint-disable jest/require-top-level-describe */ import { existsSync, rmdirSync, rmSync } from 'fs' import path from 'path' import { buildConfig, getPayload } from 'payload' import { fileURLToPath } from 'url' +import { describe, it } from 'vitest' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) -const describe = - process.env.PAYLOAD_DATABASE === 'postgres' ? global.describe : global.describe.skip +const describeToUse = process.env.PAYLOAD_DATABASE === 'postgres' ? describe : describe.skip const clearMigrations = () => { if (existsSync(path.resolve(dirname, 'migrations'))) { @@ -16,9 +15,8 @@ const clearMigrations = () => { } } -describe('SQL migrations', () => { +describeToUse('SQL migrations', () => { // If something fails - an error will be thrown. - // eslint-disable-next-line jest/expect-expect it('should up and down migration successfully', async () => { clearMigrations() diff --git a/test/database/up-down-migration/migrations/20250811_134524.json b/test/database/up-down-migration/migrations/20251030_115916.json similarity index 98% rename from test/database/up-down-migration/migrations/20250811_134524.json rename to test/database/up-down-migration/migrations/20251030_115916.json index 208ae18fed4..bbe333ce9ae 100644 --- a/test/database/up-down-migration/migrations/20250811_134524.json +++ b/test/database/up-down-migration/migrations/20251030_115916.json @@ -1,5 +1,5 @@ { - "id": "fc114c71-8138-46c6-b83a-4d70e79e0ea5", + "id": "ca9e6f22-341d-40bc-82b0-11e39ae3c549", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", @@ -393,8 +393,8 @@ } }, "foreignKeys": { - "payload_locked_documents_rels_parent_fk": { - "name": "payload_locked_documents_rels_parent_fk", + "payload_locked_documents_rels_parent_1_idx": { + "name": "payload_locked_documents_rels_parent_1_idx", "tableFrom": "payload_locked_documents_rels", "tableTo": "payload_locked_documents", "columnsFrom": ["parent_id"], @@ -607,8 +607,8 @@ } }, "foreignKeys": { - "payload_preferences_rels_parent_fk": { - "name": "payload_preferences_rels_parent_fk", + "payload_preferences_rels_parent_1_idx": { + "name": "payload_preferences_rels_parent_1_idx", "tableFrom": "payload_preferences_rels", "tableTo": "payload_preferences", "columnsFrom": ["parent_id"], diff --git a/test/database/up-down-migration/migrations/20250811_134524.ts b/test/database/up-down-migration/migrations/20251030_115916.ts similarity index 93% rename from test/database/up-down-migration/migrations/20250811_134524.ts rename to test/database/up-down-migration/migrations/20251030_115916.ts index b473da25043..023ed7cc640 100644 --- a/test/database/up-down-migration/migrations/20250811_134524.ts +++ b/test/database/up-down-migration/migrations/20251030_115916.ts @@ -1,4 +1,4 @@ -import type { MigrateDownArgs, MigrateUpArgs } from '@payloadcms/db-postgres' +import type { MigrateDownArgs, MigrateUpArgs} from '@payloadcms/db-postgres'; import { sql } from '@payloadcms/db-postgres' @@ -65,9 +65,9 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise { ); ALTER TABLE "users_sessions" ADD CONSTRAINT "users_sessions_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_locked_documents"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_parent_1_idx" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_locked_documents"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; - ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_preferences"("id") ON DELETE cascade ON UPDATE no action; + ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_1_idx" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_preferences"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; CREATE INDEX "users_sessions_order_idx" ON "users_sessions" USING btree ("_order"); CREATE INDEX "users_sessions_parent_id_idx" ON "users_sessions" USING btree ("_parent_id"); diff --git a/test/database/up-down-migration/migrations/index.ts b/test/database/up-down-migration/migrations/index.ts index 5dc4ad50458..2ced8fe37b8 100644 --- a/test/database/up-down-migration/migrations/index.ts +++ b/test/database/up-down-migration/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20250811_134524 from './20250811_134524.js' +import * as migration_20251030_115916 from './20251030_115916.js' export const migrations = [ { - up: migration_20250811_134524.up, - down: migration_20250811_134524.down, - name: '20250811_134524', + up: migration_20251030_115916.up, + down: migration_20251030_115916.down, + name: '20251030_115916', }, ] diff --git a/test/dataloader/int.spec.ts b/test/dataloader/int.spec.ts index b63f46ca631..d4fe17abd34 100644 --- a/test/dataloader/int.spec.ts +++ b/test/dataloader/int.spec.ts @@ -3,6 +3,7 @@ import type { CollectionSlug, Payload } from 'payload' import path from 'path' import { createLocalReq } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it, vitest } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' @@ -192,7 +193,7 @@ describe('dataloader', () => { describe('find', () => { it('should call the same query only once in a request', async () => { const req = await createLocalReq({}, payload) - const spy = jest.spyOn(payload, 'find') + const spy = vitest.spyOn(payload, 'find') const findArgs = { collection: 'items' as CollectionSlug, diff --git a/test/endpoints/int.spec.ts b/test/endpoints/int.spec.ts index 7d31ffd6273..871bc3a46ec 100644 --- a/test/endpoints/int.spec.ts +++ b/test/endpoints/int.spec.ts @@ -1,6 +1,7 @@ import path from 'path' import { type Payload } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/fields-relationship/int.spec.ts b/test/fields-relationship/int.spec.ts index e6b458221b1..2d0938edd24 100644 --- a/test/fields-relationship/int.spec.ts +++ b/test/fields-relationship/int.spec.ts @@ -1,4 +1,5 @@ import type { Payload } from 'payload' +import { describe, beforeAll, afterAll, it, expect } from 'vitest' import path from 'path' import { fileURLToPath } from 'url' diff --git a/test/fields/int.spec.ts b/test/fields/int.spec.ts index cb3a25a6700..d7c5b2249fb 100644 --- a/test/fields/int.spec.ts +++ b/test/fields/int.spec.ts @@ -4,6 +4,7 @@ import type { IndexDirection, IndexOptions } from 'mongoose' import path from 'path' import { type Payload, reload } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { BlockField, GroupField } from './payload-types.js' @@ -774,7 +775,6 @@ describe('Fields', () => { expect(res.docs.every(filter)).toBe(true) expect(dataSample.filter(filter)).toHaveLength(res.totalDocs) - // eslint-disable-next-line jest/no-conditional-in-test if (res.totalDocs > 10) { // This is where postgres might fail! selectDistinct actually removed some rows here, because it distincts by: // not only ID, but also created_at, updated_at, items_date @@ -3402,7 +3402,6 @@ describe('Fields', () => { }) it('should query deeply', async () => { - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name === 'sqlite') { return } diff --git a/test/folders-browse-by-disabled/int.spec.ts b/test/folders-browse-by-disabled/int.spec.ts index 17afb242a8d..63ed9c2c405 100644 --- a/test/folders-browse-by-disabled/int.spec.ts +++ b/test/folders-browse-by-disabled/int.spec.ts @@ -2,17 +2,19 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' + let payload: Payload let restClient: NextRESTClient const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) -describe('folders', () => { +describe('folders-browse-by-disabled', () => { beforeAll(async () => { ;({ payload, restClient } = await initPayloadInt(dirname)) }) diff --git a/test/folders/int.spec.ts b/test/folders/int.spec.ts index 88517be9e45..c45d918b53e 100644 --- a/test/folders/int.spec.ts +++ b/test/folders/int.spec.ts @@ -2,8 +2,10 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import { initPayloadInt } from '../helpers/initPayloadInt.js' + let payload: Payload const filename = fileURLToPath(import.meta.url) diff --git a/test/form-state/int.spec.ts b/test/form-state/int.spec.ts index 176d1cad679..2b0231168e3 100644 --- a/test/form-state/int.spec.ts +++ b/test/form-state/int.spec.ts @@ -5,6 +5,7 @@ import { buildFormState } from '@payloadcms/ui/utilities/buildFormState' import path from 'path' import { createLocalReq } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/globals/int.spec.ts b/test/globals/int.spec.ts index 19315ec702f..ee09d8fdeb3 100644 --- a/test/globals/int.spec.ts +++ b/test/globals/int.spec.ts @@ -2,6 +2,7 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/graphql/int.spec.ts b/test/graphql/int.spec.ts index 8946d81b77a..5c744b92d73 100644 --- a/test/graphql/int.spec.ts +++ b/test/graphql/int.spec.ts @@ -2,6 +2,7 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/helpers.ts b/test/helpers.ts index a4ea5f27d00..c73f3c293d4 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -10,7 +10,6 @@ import type { Config, SanitizedConfig } from 'payload' import { expect } from '@playwright/test' import { defaults } from 'payload' import { formatAdminURL, wait } from 'payload/shared' -import shelljs from 'shelljs' import { setTimeout } from 'timers/promises' import { POLL_TOPASS_TIMEOUT } from './playwright.config.js' @@ -397,24 +396,6 @@ export function initPageConsoleErrorCatch(page: Page, options?: { ignoreCORS?: b } } -export function describeIfInCIOrHasLocalstack(): jest.Describe { - if (process.env.CI) { - return describe - } - - // Check that localstack is running - const { code } = shelljs.exec(`docker ps | grep localstack`) - - if (code !== 0) { - console.warn('Localstack is not running. Skipping test suite.') - return describe.skip - } - - console.log('Localstack is running. Running test suite.') - - return describe -} - export function getRoutes({ customAdminRoutes, customRoutes, diff --git a/test/helpers/isMongoose.ts b/test/helpers/isMongoose.ts index 3343d292793..f04589147a6 100644 --- a/test/helpers/isMongoose.ts +++ b/test/helpers/isMongoose.ts @@ -1,6 +1,6 @@ import type { Payload } from 'payload' -export const mongooseList = ['cosmosdb', 'documentdb', 'firestore', 'mongodb'] +export const mongooseList = ['cosmosdb', 'documentdb', 'firestore', 'mongodb', 'mongodb-atlas'] export function isMongoose(_payload?: Payload) { return _payload?.db?.name === 'mongoose' || mongooseList.includes(process.env.PAYLOAD_DATABASE) diff --git a/test/hooks/int.spec.ts b/test/hooks/int.spec.ts index 122bfc8bbc9..a639391ed99 100644 --- a/test/hooks/int.spec.ts +++ b/test/hooks/int.spec.ts @@ -3,6 +3,7 @@ import type { Payload } from 'payload' import path from 'path' import { AuthenticationError } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/jest.config.js b/test/jest.config.js deleted file mode 100644 index 6bd176af962..00000000000 --- a/test/jest.config.js +++ /dev/null @@ -1,22 +0,0 @@ -import path from 'path' -import { fileURLToPath } from 'url' -import jestBaseConfig from '../jest.config.js' - -const filename = fileURLToPath(import.meta.url) -const dirname = path.dirname(filename) - -/** @type {import('jest').Config} */ -const customJestConfig = { - ...jestBaseConfig, - testMatch: ['/**/*int.spec.ts'], - setupFilesAfterEnv: ['/jest.setup.js'], - - moduleNameMapper: { - '\\.(css|scss)$': '/helpers/mocks/emptyModule.js', - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': - '/helpers/mocks/fileMock.js', - '^(\\.{1,2}/.*)\\.js$': '$1', - }, -} - -export default customJestConfig diff --git a/test/joins/int.spec.ts b/test/joins/int.spec.ts index 878963ba899..07371aee64b 100644 --- a/test/joins/int.spec.ts +++ b/test/joins/int.spec.ts @@ -3,6 +3,7 @@ import type { Payload, TypeWithID } from 'payload' import path from 'path' import { getFileByPath } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { Category, Config, DepthJoins1, DepthJoins3, Post, Singular } from './payload-types.js' diff --git a/test/kv/int.spec.ts b/test/kv/int.spec.ts index f65741ee5a9..f845467a537 100644 --- a/test/kv/int.spec.ts +++ b/test/kv/int.spec.ts @@ -4,6 +4,7 @@ import { RedisKVAdapter, redisKVAdapter } from '@payloadcms/kv-redis' import path from 'path' import { inMemoryKVAdapter } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import { initPayloadInt } from '../helpers/initPayloadInt.js' diff --git a/test/lexical-mdx/int.spec.ts b/test/lexical-mdx/int.spec.ts index 76b9d0e3115..63b62637194 100644 --- a/test/lexical-mdx/int.spec.ts +++ b/test/lexical-mdx/int.spec.ts @@ -1,4 +1,3 @@ -/* eslint jest/no-conditional-in-test: 0 */ import type { BlockFields, LexicalRichTextAdapter, @@ -8,19 +7,19 @@ import type { import type { RichTextField, SanitizedConfig } from 'payload' import type { MarkOptional } from 'ts-essentials' +import { writeFileSync } from 'fs' import path from 'path' import { fileURLToPath } from 'url' +import { beforeAll, describe, expect, it } from 'vitest' import { initPayloadInt } from '../helpers/initPayloadInt.js' import { postsSlug } from './collections/Posts/index.js' import { editorJSONToMDX, mdxToEditorJSON } from './mdx/hooks.js' +import { codeTest1 } from './tests/code1.test.js' +import { defaultTests } from './tests/default.test.js' import { restExamplesTest1 } from './tests/restExamples.test.js' import { restExamplesTest2 } from './tests/restExamples2.test.js' -import { defaultTests } from './tests/default.test.js' -import { writeFileSync } from 'fs' -import { codeTest1 } from './tests/code1.test.js' - let config: SanitizedConfig let editorConfig: SanitizedServerEditorConfig @@ -34,14 +33,14 @@ export type Test = { MarkOptional, 'fields' > + convertFromEditorJSON?: boolean + convertToEditorJSON?: boolean debugFlag?: boolean description?: string ignoreSpacesAndNewlines?: boolean input: string inputAfterConvertFromEditorJSON?: string rootChildren?: any[] - convertToEditorJSON?: boolean - convertFromEditorJSON?: boolean } type Tests = Array diff --git a/test/lexical/lexical.int.spec.ts b/test/lexical/lexical.int.spec.ts index fc231834308..121c4423f46 100644 --- a/test/lexical/lexical.int.spec.ts +++ b/test/lexical/lexical.int.spec.ts @@ -4,7 +4,6 @@ import type { } from '@payloadcms/richtext-lexical/lexical' import type { PaginatedDocs, Payload } from 'payload' -/* eslint-disable jest/no-conditional-in-test */ import { buildEditorState, type DefaultNodeTypes, @@ -15,6 +14,7 @@ import { } from '@payloadcms/richtext-lexical' import path from 'path' import { fileURLToPath } from 'url' +import { beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { LexicalField, LexicalMigrateField, RichTextField } from './payload-types.js' diff --git a/test/live-preview/int.spec.ts b/test/live-preview/int.spec.ts index f7163c1effe..fd24ee88e7c 100644 --- a/test/live-preview/int.spec.ts +++ b/test/live-preview/int.spec.ts @@ -8,6 +8,7 @@ import { import path from 'path' import { getFileByPath } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { Media, Page, Post, Tenant } from './payload-types.js' @@ -900,12 +901,10 @@ describe('Collections - Live Preview', () => { expect(merge2[fieldName].root.children[3].value).toMatchObject(media) } - // eslint-disable-next-line jest/expect-expect it('— relationships - populates within Lexical rich text editor', async () => { await lexicalTest('richTextLexical') }) - // eslint-disable-next-line jest/expect-expect it('— relationships - populates within Localized Lexical rich text editor', async () => { await lexicalTest('richTextLexicalLocalized') }) diff --git a/test/loader/int.spec.ts b/test/loader/int.spec.ts index fda76944faa..3e55c07157e 100644 --- a/test/loader/int.spec.ts +++ b/test/loader/int.spec.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'vitest' + import { startChildProcess } from './startChildProcess.js' describe('Loader', () => { diff --git a/test/localization/int.spec.ts b/test/localization/int.spec.ts index d25ccd2b3c4..502a6c24bdd 100644 --- a/test/localization/int.spec.ts +++ b/test/localization/int.spec.ts @@ -3,6 +3,7 @@ import type { Payload, User, Where } from 'payload' import path from 'path' import { createLocalReq } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { @@ -1269,7 +1270,6 @@ describe('Localization', () => { locale: spanishLocale, }) - // eslint-disable-next-line jest/no-conditional-in-test if (isMongoose(payload)) { expect(docWithoutFallback.items).toStrictEqual(null) } else { diff --git a/test/locked-documents/int.spec.ts b/test/locked-documents/int.spec.ts index 487f6400e90..60f5e1e1ade 100644 --- a/test/locked-documents/int.spec.ts +++ b/test/locked-documents/int.spec.ts @@ -1,4 +1,5 @@ import type { Payload, SanitizedCollectionConfig, SanitizedGlobalConfig } from 'payload' +import { describe, beforeAll, afterAll, afterEach, it, expect } from 'vitest' import path from 'path' import { Locked, NotFound } from 'payload' diff --git a/test/login-with-username/int.spec.ts b/test/login-with-username/int.spec.ts index 66c2cbed578..26c6edf313e 100644 --- a/test/login-with-username/int.spec.ts +++ b/test/login-with-username/int.spec.ts @@ -2,6 +2,7 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import { devUser } from '../credentials.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' diff --git a/test/package.json b/test/package.json index 144b6b3173c..965d2b824e7 100644 --- a/test/package.json +++ b/test/package.json @@ -77,9 +77,8 @@ "@sentry/react": "^7.77.0", "@stripe/react-stripe-js": "3.7.0", "@stripe/stripe-js": "7.3.1", - "@types/jest": "29.5.12", - "@types/react": "19.2.1", - "@types/react-dom": "19.2.1", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "babel-plugin-react-compiler": "19.1.0-rc.3", "better-sqlite3": "11.10.0", "comment-json": "^4.2.3", @@ -94,7 +93,6 @@ "execa": "5.1.1", "file-type": "19.3.0", "http-status": "2.1.0", - "jest": "29.7.0", "jwt-decode": "4.0.0", "mongoose": "8.15.1", "next": "15.4.10", @@ -113,10 +111,14 @@ "ts-essentials": "10.0.3", "typescript": "5.7.3", "uuid": "10.0.0", + "vitest": "4.0.15", "wrangler": "~4.42.0", "zod": "^3.25.5" }, "pnpm": { - "neverBuiltDependencies": [] + "neverBuiltDependencies": [], + "overrides": { + "graphql": "16.8.1" + } } } diff --git a/test/payload-cloud/int.spec.ts b/test/payload-cloud/int.spec.ts index 75d1682332b..99f6c0ca022 100644 --- a/test/payload-cloud/int.spec.ts +++ b/test/payload-cloud/int.spec.ts @@ -1,6 +1,7 @@ import path from 'path' import { type Payload } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/plugin-cloud-storage/int.spec.ts b/test/plugin-cloud-storage/int.spec.ts index db3b64a77ab..a5e29a4bd65 100644 --- a/test/plugin-cloud-storage/int.spec.ts +++ b/test/plugin-cloud-storage/int.spec.ts @@ -1,12 +1,14 @@ import type { Payload } from 'payload' +import type { SuiteAPI } from 'vitest' import * as AWS from '@aws-sdk/client-s3' import path from 'path' +import shelljs from 'shelljs' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest' import type { Config } from './payload-types.js' -import { describeIfInCIOrHasLocalstack } from '../helpers.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' import { mediaSlug, mediaWithPrefixSlug, prefix } from './shared.js' import { clearTestBucket, createTestBucket } from './utils.js' @@ -16,6 +18,25 @@ const dirname = path.dirname(filename) let payload: Payload +// needs to be here as it imports vitest functions and conflicts with playwright that uses jest +export function describeIfInCIOrHasLocalstack(): SuiteAPI | SuiteAPI['skip'] { + if (process.env.CI) { + return describe + } + + // Check that localstack is running + const { code } = shelljs.exec(`docker ps | grep localstack`) + + if (code !== 0) { + console.warn('Localstack is not running. Skipping test suite.') + return describe.skip + } + + console.log('Localstack is running. Running test suite.') + + return describe +} + describe('@payloadcms/plugin-cloud-storage', () => { let TEST_BUCKET: string diff --git a/test/plugin-ecommerce/int.spec.ts b/test/plugin-ecommerce/int.spec.ts index b31a8a817ed..66358c9fa8d 100644 --- a/test/plugin-ecommerce/int.spec.ts +++ b/test/plugin-ecommerce/int.spec.ts @@ -1,6 +1,7 @@ import path from 'path' import { type Payload } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/plugin-form-builder/int.spec.ts b/test/plugin-form-builder/int.spec.ts index 51b1af149b9..c2cb202956e 100644 --- a/test/plugin-form-builder/int.spec.ts +++ b/test/plugin-form-builder/int.spec.ts @@ -1,4 +1,5 @@ import type { Payload } from 'payload' +import { describe, beforeAll, afterAll, it, expect } from 'vitest' import path from 'path' import { ValidationError } from 'payload' diff --git a/test/plugin-import-export/int.spec.ts b/test/plugin-import-export/int.spec.ts index 571c8bc6892..f0d5f809c72 100644 --- a/test/plugin-import-export/int.spec.ts +++ b/test/plugin-import-export/int.spec.ts @@ -3,6 +3,7 @@ import type { CollectionSlug, Payload } from 'payload' import fs from 'fs' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/plugin-mcp/int.spec.ts b/test/plugin-mcp/int.spec.ts index f1620560b44..6f307150660 100644 --- a/test/plugin-mcp/int.spec.ts +++ b/test/plugin-mcp/int.spec.ts @@ -3,6 +3,7 @@ import type { Payload } from 'payload' import { randomUUID } from 'crypto' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/plugin-multi-tenant/int.spec.ts b/test/plugin-multi-tenant/int.spec.ts index c0b51c8128b..b9994881f86 100644 --- a/test/plugin-multi-tenant/int.spec.ts +++ b/test/plugin-multi-tenant/int.spec.ts @@ -2,6 +2,7 @@ import type { DefaultDocumentIDType, PaginatedDocs, Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { Relationship } from './payload-types.js' diff --git a/test/plugin-nested-docs/int.spec.ts b/test/plugin-nested-docs/int.spec.ts index 3dfb87e02cb..035012a9d51 100644 --- a/test/plugin-nested-docs/int.spec.ts +++ b/test/plugin-nested-docs/int.spec.ts @@ -2,6 +2,7 @@ import type { ArrayField, Payload, RelationshipField } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { Page } from './payload-types.js' diff --git a/test/plugin-redirects/int.spec.ts b/test/plugin-redirects/int.spec.ts index b22b08ef824..b146667da35 100644 --- a/test/plugin-redirects/int.spec.ts +++ b/test/plugin-redirects/int.spec.ts @@ -1,4 +1,5 @@ import type { Payload } from 'payload' +import { describe, beforeAll, afterAll, it, expect } from 'vitest' import path from 'path' import { fileURLToPath } from 'url' diff --git a/test/plugin-search/int.spec.ts b/test/plugin-search/int.spec.ts index fe9cf0e66ac..06452edf116 100644 --- a/test/plugin-search/int.spec.ts +++ b/test/plugin-search/int.spec.ts @@ -1,3 +1,4 @@ +import { describe, beforeAll, beforeEach, afterAll, it, expect } from 'vitest' import type { Payload } from 'payload' import path from 'path' diff --git a/test/plugin-sentry/int.spec.ts b/test/plugin-sentry/int.spec.ts index f8c8f0fd99b..c5a1b21f20f 100644 --- a/test/plugin-sentry/int.spec.ts +++ b/test/plugin-sentry/int.spec.ts @@ -1,4 +1,5 @@ import type { Payload } from 'payload' +import { describe, beforeAll, afterAll, it } from 'vitest' import path from 'path' import { fileURLToPath } from 'url' diff --git a/test/plugin-seo/int.spec.ts b/test/plugin-seo/int.spec.ts index e3c52756985..2ff292e4d2d 100644 --- a/test/plugin-seo/int.spec.ts +++ b/test/plugin-seo/int.spec.ts @@ -3,6 +3,7 @@ import type { Payload } from 'payload' import path from 'path' import { getFileByPath } from 'payload' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import { initPayloadInt } from '../helpers/initPayloadInt.js' import removeFiles from '../helpers/removeFiles.js' diff --git a/test/plugin-stripe/int.spec.ts b/test/plugin-stripe/int.spec.ts index aed0f245962..9a311a62447 100644 --- a/test/plugin-stripe/int.spec.ts +++ b/test/plugin-stripe/int.spec.ts @@ -1,4 +1,5 @@ import type { Payload } from 'payload' +import { describe, beforeAll, afterAll, it, expect } from 'vitest' import path from 'path' import { fileURLToPath } from 'url' diff --git a/test/plugins/int.spec.ts b/test/plugins/int.spec.ts index 6ab6520e732..019501b37f7 100644 --- a/test/plugins/int.spec.ts +++ b/test/plugins/int.spec.ts @@ -2,6 +2,7 @@ import type { Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import { initPayloadInt } from '../helpers/initPayloadInt.js' import { pagesSlug } from './config.js' diff --git a/test/query-presets/int.spec.ts b/test/query-presets/int.spec.ts index a62d08febbc..5d9584fe7c2 100644 --- a/test/query-presets/int.spec.ts +++ b/test/query-presets/int.spec.ts @@ -1,4 +1,5 @@ import type { Payload, User } from 'payload' +import { describe, beforeAll, afterAll, it, expect } from 'vitest' import path from 'path' import { fileURLToPath } from 'url' diff --git a/test/queues/cli.int.spec.ts b/test/queues/cli.int.spec.ts index 6b04bf43075..f7ba74946a8 100644 --- a/test/queues/cli.int.spec.ts +++ b/test/queues/cli.int.spec.ts @@ -8,6 +8,7 @@ import { } from 'payload' import { wait } from 'payload/shared' import { fileURLToPath } from 'url' +import { beforeAll, describe, expect, it } from 'vitest' import { initPayloadInt } from '../helpers/initPayloadInt.js' import { waitUntilAutorunIsDone } from './utilities.js' diff --git a/test/queues/int.spec.ts b/test/queues/int.spec.ts index a88ab501264..05a4c432db0 100644 --- a/test/queues/int.spec.ts +++ b/test/queues/int.spec.ts @@ -10,6 +10,7 @@ import { } from 'payload' import { wait } from 'payload/shared' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' @@ -1607,7 +1608,6 @@ describe('Queues - Payload', () => { }) it('can reliably run workflows with parallel tasks', async () => { - // eslint-disable-next-line jest/no-conditional-in-test if (process.env.PAYLOAD_DATABASE === 'supabase') { // TODO: This test is flaky on supabase in CI, so we skip it for now return diff --git a/test/queues/postgres-logs.int.spec.ts b/test/queues/postgres-logs.int.spec.ts index ca82344aa17..f7b5a026253 100644 --- a/test/queues/postgres-logs.int.spec.ts +++ b/test/queues/postgres-logs.int.spec.ts @@ -1,9 +1,9 @@ import type { Payload } from 'payload' -/* eslint-disable jest/require-top-level-describe */ import assert from 'assert' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it, vitest } from 'vitest' import { initPayloadInt } from '../helpers/initPayloadInt.js' import { withoutAutoRun } from './utilities.js' @@ -44,7 +44,7 @@ describePostgres('queues - postgres logs', () => { }) // Count every console log (= db call) - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) const res = await payload.jobs.run({}) diff --git a/test/queues/schedules-autocron.int.spec.ts b/test/queues/schedules-autocron.int.spec.ts index 1e9773fe11e..ebaa11fca4c 100644 --- a/test/queues/schedules-autocron.int.spec.ts +++ b/test/queues/schedules-autocron.int.spec.ts @@ -2,6 +2,7 @@ import path from 'path' import { _internal_jobSystemGlobals, _internal_resetJobSystemGlobals, type Payload } from 'payload' import { wait } from 'payload/shared' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/queues/schedules.int.spec.ts b/test/queues/schedules.int.spec.ts index 51d029600f3..c7ade505f5b 100644 --- a/test/queues/schedules.int.spec.ts +++ b/test/queues/schedules.int.spec.ts @@ -1,4 +1,5 @@ import path from 'path' +import { describe, beforeAll, afterAll, afterEach, beforeEach, it, expect } from 'vitest' import { _internal_jobSystemGlobals, _internal_resetJobSystemGlobals, type Payload } from 'payload' import { wait } from 'payload/shared' import { fileURLToPath } from 'url' diff --git a/test/relationships/int.spec.ts b/test/relationships/int.spec.ts index 03e4265f05b..21009b0de0b 100644 --- a/test/relationships/int.spec.ts +++ b/test/relationships/int.spec.ts @@ -3,6 +3,7 @@ import type { Payload, PayloadRequest } from 'payload' import { randomBytes, randomUUID } from 'crypto' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { @@ -649,7 +650,6 @@ describe('Relationships', () => { }, }) - // eslint-disable-next-line jest/no-standalone-expect expect(query1.totalDocs).toStrictEqual(1) }) @@ -1658,7 +1658,6 @@ describe('Relationships', () => { }) .then((res) => res.json()) - // eslint-disable-next-line jest/no-standalone-expect expect(queryOne.docs).toHaveLength(1) }) diff --git a/test/sdk/int.spec.ts b/test/sdk/int.spec.ts index 35b1c998f87..d38490d665f 100644 --- a/test/sdk/int.spec.ts +++ b/test/sdk/int.spec.ts @@ -3,6 +3,7 @@ import type { Payload } from 'payload' import { randomUUID } from 'crypto' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { TypedPayloadSDK } from '../helpers/getSDK.js' import type { Post } from './payload-types.js' @@ -76,7 +77,6 @@ describe('@payloadcms/sdk', () => { const result = await sdk.findByID({ disableErrors: true, collection: 'posts', - // eslint-disable-next-line jest/no-conditional-in-test id: typeof post.id === 'string' ? randomUUID() : 999, }) diff --git a/test/select/int.spec.ts b/test/select/int.spec.ts index 5ae8d5c9637..112209826fd 100644 --- a/test/select/int.spec.ts +++ b/test/select/int.spec.ts @@ -5,6 +5,7 @@ import path from 'path' import { deepCopyObject } from 'payload' import { assert } from 'ts-essentials' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { @@ -409,7 +410,6 @@ describe('Select', () => { expect(res).toStrictEqual({ id: postId, blocks: post.blocks?.map((block) => - // eslint-disable-next-line jest/no-conditional-in-test block.blockType === 'cta' ? block : { @@ -435,7 +435,6 @@ describe('Select', () => { expect(res).toStrictEqual({ id: postId, blocks: post.blocks?.map((block) => - // eslint-disable-next-line jest/no-conditional-in-test block.blockType === 'cta' ? { id: block.id, blockType: block.blockType, ctaText: block.ctaText } : { @@ -700,7 +699,6 @@ describe('Select', () => { expect(res).toStrictEqual({ ...post, blocks: post.blocks?.map((block) => - // eslint-disable-next-line jest/no-conditional-in-test block.blockType === 'cta' ? { id: block.id, blockType: block.blockType } : block, ), }) @@ -721,7 +719,6 @@ describe('Select', () => { expect(res).toStrictEqual({ ...post, blocks: post.blocks?.map((block) => { - // eslint-disable-next-line jest/no-conditional-in-test if ('ctaText' in block) { delete block['ctaText'] } @@ -732,7 +729,6 @@ describe('Select', () => { }) it('should exclude a point field', async () => { - // eslint-disable-next-line jest/no-conditional-in-test if (payload.db.name === 'sqlite') { return } @@ -1007,7 +1003,6 @@ describe('Select', () => { expect(res).toStrictEqual({ id: postId, blocks: post.blocks?.map((block) => - // eslint-disable-next-line jest/no-conditional-in-test block.blockType === 'cta' ? block : { @@ -1032,7 +1027,6 @@ describe('Select', () => { expect(res).toStrictEqual({ id: postId, blocks: post.blocks?.map((block) => - // eslint-disable-next-line jest/no-conditional-in-test block.blockType === 'cta' ? { id: block.id, blockType: block.blockType, ctaText: block.ctaText } : { @@ -1057,7 +1051,6 @@ describe('Select', () => { expect(res).toStrictEqual({ id: postId, blocksSecond: post.blocksSecond?.map((block) => - // eslint-disable-next-line jest/no-conditional-in-test block.blockType === 'second' ? { id: block.id, blockType: block.blockType, text: block.text } : { @@ -1082,7 +1075,6 @@ describe('Select', () => { expect(res).toStrictEqual({ id: postId, blocksSecond: post.blocksSecond?.map((block) => - // eslint-disable-next-line jest/no-conditional-in-test block.blockType === 'first' ? { id: block.id, blockType: block.blockType, firstText: block.firstText } : { @@ -1315,7 +1307,6 @@ describe('Select', () => { expect(res).toStrictEqual({ ...post, blocks: post.blocks?.map((block) => - // eslint-disable-next-line jest/no-conditional-in-test block.blockType === 'cta' ? { id: block.id, blockType: block.blockType } : block, ), }) @@ -1335,7 +1326,6 @@ describe('Select', () => { expect(res).toStrictEqual({ ...post, blocks: post.blocks?.map((block) => { - // eslint-disable-next-line jest/no-conditional-in-test if ('ctaText' in block) { delete block['ctaText'] } @@ -1359,7 +1349,6 @@ describe('Select', () => { expect(res).toStrictEqual({ ...post, blocksSecond: post.blocksSecond?.map((block) => { - // eslint-disable-next-line jest/no-conditional-in-test if (block.blockType === 'second') { delete block['text'] } @@ -1383,7 +1372,6 @@ describe('Select', () => { expect(res).toStrictEqual({ ...post, blocksSecond: post.blocksSecond?.map((block) => { - // eslint-disable-next-line jest/no-conditional-in-test if ('firstText' in block) { delete block['firstText'] } diff --git a/test/select/postgreslogs.int.spec.ts b/test/select/postgreslogs.int.spec.ts index 076d4758e2c..f649308e75c 100644 --- a/test/select/postgreslogs.int.spec.ts +++ b/test/select/postgreslogs.int.spec.ts @@ -1,9 +1,9 @@ -/* eslint-disable jest/require-top-level-describe */ import type { Payload } from 'payload' import path from 'path' import { assert } from 'ts-essentials' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vitest } from 'vitest' import type { Point, Post } from './payload-types.js' @@ -61,7 +61,7 @@ describePostgres('Select - with postgres logs', () => { const post = await createPost() // Count every console log - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) const res = removeEmptyAndUndefined( (await payload.db.updateOne({ @@ -103,7 +103,7 @@ describePostgres('Select - with postgres logs', () => { }) // Count every console log - const consoleCount = jest.spyOn(console, 'log').mockImplementation(() => {}) + const consoleCount = vitest.spyOn(console, 'log').mockImplementation(() => {}) const res = removeEmptyAndUndefined( (await payload.db.updateOne({ diff --git a/test/sort/int.spec.ts b/test/sort/int.spec.ts index ba25fad7ef9..1512c0a8ec7 100644 --- a/test/sort/int.spec.ts +++ b/test/sort/int.spec.ts @@ -2,6 +2,7 @@ import type { CollectionSlug, Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { Draft, Orderable, OrderableJoin } from './payload-types.js' diff --git a/test/storage-azure/int.spec.ts b/test/storage-azure/int.spec.ts index 14cc8c9d13e..40c81c74952 100644 --- a/test/storage-azure/int.spec.ts +++ b/test/storage-azure/int.spec.ts @@ -4,6 +4,7 @@ import type { CollectionSlug, Payload } from 'payload' import { BlobServiceClient } from '@azure/storage-blob' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' @@ -31,7 +32,7 @@ describe('@payloadcms/storage-azure', () => { await client.createIfNotExists() await clearContainer() - }) + }, 90000) afterAll(async () => { await payload.destroy() diff --git a/test/storage-s3/int.spec.ts b/test/storage-s3/int.spec.ts index 5c661ac4752..7aaccf63830 100644 --- a/test/storage-s3/int.spec.ts +++ b/test/storage-s3/int.spec.ts @@ -3,6 +3,7 @@ import type { CollectionSlug, Payload } from 'payload' import * as AWS from '@aws-sdk/client-s3' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/trash/int.spec.ts b/test/trash/int.spec.ts index 774143a2d9d..ef0353d64aa 100644 --- a/test/trash/int.spec.ts +++ b/test/trash/int.spec.ts @@ -2,6 +2,7 @@ import type { CollectionSlug, Payload } from 'payload' import path from 'path' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { Post, RestrictedCollection } from './payload-types.js' diff --git a/test/tsconfig.json b/test/tsconfig.json index c6e6077dfc8..a8671bb75d3 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -18,7 +18,7 @@ "lib": ["DOM", "DOM.Iterable", "ES2022"], "resolveJsonModule": true, "skipLibCheck": true, - "types": ["jest", "node", "@types/jest"], + "types": ["node"], "incremental": true, "isolatedModules": true, "plugins": [ diff --git a/test/uploads/int.spec.ts b/test/uploads/int.spec.ts index 4644d1e9095..d92a28095ff 100644 --- a/test/uploads/int.spec.ts +++ b/test/uploads/int.spec.ts @@ -8,6 +8,7 @@ import path from 'path' import { _internal_safeFetchGlobal, createPayloadRequest, getFileByPath } from 'payload' import { fileURLToPath } from 'url' import { promisify } from 'util' +import { afterAll, beforeAll, describe, expect, it, vitest } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { Enlarge, Media } from './payload-types.js' @@ -768,7 +769,7 @@ describe('Collections - Uploads', () => { '; ', ) - const fetchSpy = jest.spyOn(global, 'fetch') + const fetchSpy = vitest.spyOn(global, 'fetch') await payload.create({ collection: skipSafeFetchMediaSlug, @@ -798,7 +799,7 @@ describe('Collections - Uploads', () => { '; ', ) - const fetchSpy = jest.spyOn(global, 'fetch') + const fetchSpy = vitest.spyOn(global, 'fetch') // spin up a temporary server so fetch to the local doesn't fail const server = createServer((req, res) => { @@ -842,7 +843,7 @@ describe('Collections - Uploads', () => { '; ', ) - const fetchSpy = jest.spyOn(global, 'fetch') + const fetchSpy = vitest.spyOn(global, 'fetch') await payload.create({ collection: skipSafeFetchHeaderFilterSlug, @@ -899,7 +900,6 @@ describe('Collections - Uploads', () => { const isIPV6 = hostname.includes('::') // Strip brackets from IPv6 addresses - // eslint-disable-next-line jest/no-conditional-in-test if (isIPV6) { hostname = hostname.slice(1, -1) } @@ -908,7 +908,6 @@ describe('Collections - Uploads', () => { // we'd like to test for // @ts-expect-error this does not need to be mocked 100% correctly _internal_safeFetchGlobal.lookup = (_hostname, _options, callback) => { - // eslint-disable-next-line jest/no-conditional-in-test callback(null, hostname as any, isIPV6 ? 6 : 4) } diff --git a/test/versions/int.spec.ts b/test/versions/int.spec.ts index dfb9560f576..d48214cdb0e 100644 --- a/test/versions/int.spec.ts +++ b/test/versions/int.spec.ts @@ -6,6 +6,7 @@ import { createLocalReq, ValidationError } from 'payload' import { wait } from 'payload/shared' import * as qs from 'qs-esm' import { fileURLToPath } from 'url' +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest' import type { NextRESTClient } from '../helpers/NextRESTClient.js' import type { AutosaveMultiSelectPost, DraftPost } from './payload-types.js' diff --git a/test/jest.setup.js b/test/vitest.setup.ts similarity index 63% rename from test/jest.setup.js rename to test/vitest.setup.ts index 0a965121df4..732a881c8f4 100644 --- a/test/jest.setup.js +++ b/test/vitest.setup.ts @@ -1,11 +1,10 @@ -import { jest } from '@jest/globals' import console from 'console' global.console = console import dotenv from 'dotenv' dotenv.config() -import nodemailer from 'nodemailer' +// import nodemailer from 'nodemailer' import { generateDatabaseAdapter } from './generateDatabaseAdapter.js' @@ -20,17 +19,17 @@ process.env.PAYLOAD_CI_DEPENDENCY_CHECKER = 'true' // @todo remove in 4.0 - will behave like this by default in 4.0 process.env.PAYLOAD_DO_NOT_SANITIZE_LOCALIZED_PROPERTY = 'true' -// Mock createTestAccount to prevent calling external services -jest.spyOn(nodemailer, 'createTestAccount').mockImplementation(() => { - return Promise.resolve({ - imap: { host: 'imap.test.com', port: 993, secure: true }, - pass: 'testpass', - pop3: { host: 'pop3.test.com', port: 995, secure: true }, - smtp: { host: 'smtp.test.com', port: 587, secure: false }, - user: 'testuser', - web: 'https://webmail.test.com', - }) -}) +// // Mock createTestAccount to prevent calling external services +// jest.spyOn(nodemailer, 'createTestAccount').mockImplementation(() => { +// return Promise.resolve({ +// imap: { host: 'imap.test.com', port: 993, secure: true }, +// pass: 'testpass', +// pop3: { host: 'pop3.test.com', port: 995, secure: true }, +// smtp: { host: 'smtp.test.com', port: 587, secure: false }, +// user: 'testuser', +// web: 'https://webmail.test.com', +// }) +// }) if (!process.env.PAYLOAD_DATABASE) { // Mutate env so we can use conditions by DB adapter in tests properly without ignoring // eslint no-jest-conditions. diff --git a/tsconfig.base.json b/tsconfig.base.json index c79d70dc84f..4ea13ef00ca 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -22,7 +22,7 @@ "emitDeclarationOnly": true, "sourceMap": true, "lib": ["DOM", "DOM.Iterable", "ES2022"], - "types": ["node", "jest"], + "types": ["node"], "incremental": true, "isolatedModules": true, "plugins": [ diff --git a/tsconfig.json b/tsconfig.json index ec0ce83f7c8..4e094666f3e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -94,6 +94,6 @@ "include": [ "${configDir}/src", ".next/types/**/*.ts", - "./scripts/**/*.ts", + "./scripts/**/*.ts" ] } diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000000..83e0e173b48 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,32 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + watch: false, // too troublesome especially with the in memory DB setup + projects: [ + { + test: { + include: ['packages/**/*.spec.ts'], + name: 'unit', + environment: 'node', + }, + }, + { + resolve: { + alias: { + graphql: 'node_modules/graphql/index.js', // https://github.com/vitest-dev/vitest/issues/4605 + }, + }, + test: { + include: ['test/**/*int.spec.ts'], + name: 'int', + environment: 'node', + fileParallelism: false, + hookTimeout: 90000, + testTimeout: 90000, + setupFiles: ['./test/vitest.setup.ts'], + }, + }, + ], + }, +}) From f5c84e5f4e900b0925b073e97536804e3c350b37 Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Fri, 19 Dec 2025 16:37:22 -0500 Subject: [PATCH 35/67] chore(release): v3.69.0 [skip ci] --- package.json | 2 +- packages/admin-bar/package.json | 2 +- packages/create-payload-app/package.json | 2 +- packages/db-d1-sqlite/package.json | 2 +- packages/db-mongodb/package.json | 2 +- packages/db-postgres/package.json | 2 +- packages/db-sqlite/package.json | 2 +- packages/db-vercel-postgres/package.json | 2 +- packages/drizzle/package.json | 2 +- packages/email-nodemailer/package.json | 2 +- packages/email-resend/package.json | 2 +- packages/graphql/package.json | 2 +- packages/kv-redis/package.json | 2 +- packages/live-preview-react/package.json | 2 +- packages/live-preview-vue/package.json | 2 +- packages/live-preview/package.json | 2 +- packages/next/package.json | 2 +- packages/payload-cloud/package.json | 2 +- packages/payload/package.json | 2 +- packages/plugin-cloud-storage/package.json | 2 +- packages/plugin-ecommerce/package.json | 2 +- packages/plugin-form-builder/package.json | 2 +- packages/plugin-import-export/package.json | 2 +- packages/plugin-mcp/package.json | 2 +- packages/plugin-multi-tenant/package.json | 2 +- packages/plugin-nested-docs/package.json | 2 +- packages/plugin-redirects/package.json | 2 +- packages/plugin-search/package.json | 2 +- packages/plugin-sentry/package.json | 2 +- packages/plugin-seo/package.json | 2 +- packages/plugin-stripe/package.json | 2 +- packages/richtext-lexical/package.json | 2 +- packages/richtext-slate/package.json | 2 +- packages/sdk/package.json | 2 +- packages/storage-azure/package.json | 2 +- packages/storage-gcs/package.json | 2 +- packages/storage-r2/package.json | 2 +- packages/storage-s3/package.json | 2 +- packages/storage-uploadthing/package.json | 2 +- packages/storage-vercel-blob/package.json | 2 +- packages/translations/package.json | 2 +- packages/ui/package.json | 2 +- 42 files changed, 42 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 438ad3c4fe4..7225bd02a34 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload-monorepo", - "version": "3.68.5", + "version": "3.69.0", "private": true, "type": "module", "workspaces": [ diff --git a/packages/admin-bar/package.json b/packages/admin-bar/package.json index 854efc64a31..2471a6fa6e2 100644 --- a/packages/admin-bar/package.json +++ b/packages/admin-bar/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/admin-bar", - "version": "3.68.5", + "version": "3.69.0", "description": "An admin bar for React apps using Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/create-payload-app/package.json b/packages/create-payload-app/package.json index e8c3c4752a3..2cd28a8ca54 100644 --- a/packages/create-payload-app/package.json +++ b/packages/create-payload-app/package.json @@ -1,6 +1,6 @@ { "name": "create-payload-app", - "version": "3.68.5", + "version": "3.69.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/db-d1-sqlite/package.json b/packages/db-d1-sqlite/package.json index d2a103ab0ab..d3fcfc6a2fb 100644 --- a/packages/db-d1-sqlite/package.json +++ b/packages/db-d1-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-d1-sqlite", - "version": "3.68.5", + "version": "3.69.0", "description": "The officially supported D1 SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-mongodb/package.json b/packages/db-mongodb/package.json index c8447cec23f..728988f1d1e 100644 --- a/packages/db-mongodb/package.json +++ b/packages/db-mongodb/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-mongodb", - "version": "3.68.5", + "version": "3.69.0", "description": "The officially supported MongoDB database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-postgres/package.json b/packages/db-postgres/package.json index 3df472b8812..ecead2a66dc 100644 --- a/packages/db-postgres/package.json +++ b/packages/db-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-postgres", - "version": "3.68.5", + "version": "3.69.0", "description": "The officially supported Postgres database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-sqlite/package.json b/packages/db-sqlite/package.json index 61136bd4d19..efe7db13be9 100644 --- a/packages/db-sqlite/package.json +++ b/packages/db-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-sqlite", - "version": "3.68.5", + "version": "3.69.0", "description": "The officially supported SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-vercel-postgres/package.json b/packages/db-vercel-postgres/package.json index 0b7a6c84462..32fb9c1139b 100644 --- a/packages/db-vercel-postgres/package.json +++ b/packages/db-vercel-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-vercel-postgres", - "version": "3.68.5", + "version": "3.69.0", "description": "Vercel Postgres adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/drizzle/package.json b/packages/drizzle/package.json index 349cc488e7d..2519e481b68 100644 --- a/packages/drizzle/package.json +++ b/packages/drizzle/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/drizzle", - "version": "3.68.5", + "version": "3.69.0", "description": "A library of shared functions used by different payload database adapters", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-nodemailer/package.json b/packages/email-nodemailer/package.json index b7eb6cbbc04..26e24c6e467 100644 --- a/packages/email-nodemailer/package.json +++ b/packages/email-nodemailer/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-nodemailer", - "version": "3.68.5", + "version": "3.69.0", "description": "Payload Nodemailer Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-resend/package.json b/packages/email-resend/package.json index cbd5c99fa60..a15b5cf7cb6 100644 --- a/packages/email-resend/package.json +++ b/packages/email-resend/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-resend", - "version": "3.68.5", + "version": "3.69.0", "description": "Payload Resend Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/graphql/package.json b/packages/graphql/package.json index 759a1c39a81..b2ec5b06332 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/graphql", - "version": "3.68.5", + "version": "3.69.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/kv-redis/package.json b/packages/kv-redis/package.json index d96ab21e31b..8c452544dd1 100644 --- a/packages/kv-redis/package.json +++ b/packages/kv-redis/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/kv-redis", - "version": "3.68.5", + "version": "3.69.0", "description": "Redis KV adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-react/package.json b/packages/live-preview-react/package.json index 6b4f2e40c54..540e99a2b1a 100644 --- a/packages/live-preview-react/package.json +++ b/packages/live-preview-react/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-react", - "version": "3.68.5", + "version": "3.69.0", "description": "The official React SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-vue/package.json b/packages/live-preview-vue/package.json index 3630845e727..a69aae56914 100644 --- a/packages/live-preview-vue/package.json +++ b/packages/live-preview-vue/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-vue", - "version": "3.68.5", + "version": "3.69.0", "description": "The official Vue SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview/package.json b/packages/live-preview/package.json index 92b305fcdb3..eba6fe3e8c2 100644 --- a/packages/live-preview/package.json +++ b/packages/live-preview/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview", - "version": "3.68.5", + "version": "3.69.0", "description": "The official live preview JavaScript SDK for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/next/package.json b/packages/next/package.json index cec82fb2914..c132714303e 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/next", - "version": "3.68.5", + "version": "3.69.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index e82cb3ff77a..155cdd15f9a 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/payload-cloud", - "version": "3.68.5", + "version": "3.69.0", "description": "The official Payload Cloud plugin", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/payload/package.json b/packages/payload/package.json index 0d7c1af0010..80c7e4b9e3b 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "3.68.5", + "version": "3.69.0", "description": "Node, React, Headless CMS and Application Framework built on Next.js", "keywords": [ "admin panel", diff --git a/packages/plugin-cloud-storage/package.json b/packages/plugin-cloud-storage/package.json index cba90239349..c52fe23ebe3 100644 --- a/packages/plugin-cloud-storage/package.json +++ b/packages/plugin-cloud-storage/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-cloud-storage", - "version": "3.68.5", + "version": "3.69.0", "description": "The official cloud storage plugin for Payload CMS", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-ecommerce/package.json b/packages/plugin-ecommerce/package.json index 1512d35e574..026bcd32bea 100644 --- a/packages/plugin-ecommerce/package.json +++ b/packages/plugin-ecommerce/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-ecommerce", - "version": "3.68.5", + "version": "3.69.0", "description": "Ecommerce plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-form-builder/package.json b/packages/plugin-form-builder/package.json index a21d0ab7b12..e42e26ebad5 100644 --- a/packages/plugin-form-builder/package.json +++ b/packages/plugin-form-builder/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-form-builder", - "version": "3.68.5", + "version": "3.69.0", "description": "Form builder plugin for Payload CMS", "keywords": [ "payload", diff --git a/packages/plugin-import-export/package.json b/packages/plugin-import-export/package.json index de6a46ed83d..94d19ad7fdd 100644 --- a/packages/plugin-import-export/package.json +++ b/packages/plugin-import-export/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-import-export", - "version": "3.68.5", + "version": "3.69.0", "description": "Import-Export plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-mcp/package.json b/packages/plugin-mcp/package.json index 78828d1acc4..2793bfb941b 100644 --- a/packages/plugin-mcp/package.json +++ b/packages/plugin-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-mcp", - "version": "3.68.5", + "version": "3.69.0", "description": "MCP (Model Context Protocol) capabilities with Payload", "keywords": [ "plugin", diff --git a/packages/plugin-multi-tenant/package.json b/packages/plugin-multi-tenant/package.json index 0297f95544b..adaa951ecaa 100644 --- a/packages/plugin-multi-tenant/package.json +++ b/packages/plugin-multi-tenant/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-multi-tenant", - "version": "3.68.5", + "version": "3.69.0", "description": "Multi Tenant plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-nested-docs/package.json b/packages/plugin-nested-docs/package.json index 5019b68a6ca..b32afde31be 100644 --- a/packages/plugin-nested-docs/package.json +++ b/packages/plugin-nested-docs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-nested-docs", - "version": "3.68.5", + "version": "3.69.0", "description": "The official Nested Docs plugin for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-redirects/package.json b/packages/plugin-redirects/package.json index 06405de51d3..6f8c74582f0 100644 --- a/packages/plugin-redirects/package.json +++ b/packages/plugin-redirects/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-redirects", - "version": "3.68.5", + "version": "3.69.0", "description": "Redirects plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-search/package.json b/packages/plugin-search/package.json index 20e92f42298..79a510b1da3 100644 --- a/packages/plugin-search/package.json +++ b/packages/plugin-search/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-search", - "version": "3.68.5", + "version": "3.69.0", "description": "Search plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-sentry/package.json b/packages/plugin-sentry/package.json index 5296b75e1e3..00ccf2b5fa6 100644 --- a/packages/plugin-sentry/package.json +++ b/packages/plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-sentry", - "version": "3.68.5", + "version": "3.69.0", "description": "Sentry plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-seo/package.json b/packages/plugin-seo/package.json index 36e64b41fee..7b00eb210b6 100644 --- a/packages/plugin-seo/package.json +++ b/packages/plugin-seo/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-seo", - "version": "3.68.5", + "version": "3.69.0", "description": "SEO plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-stripe/package.json b/packages/plugin-stripe/package.json index 4822927a45f..0b84083528c 100644 --- a/packages/plugin-stripe/package.json +++ b/packages/plugin-stripe/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-stripe", - "version": "3.68.5", + "version": "3.69.0", "description": "Stripe plugin for Payload", "keywords": [ "payload", diff --git a/packages/richtext-lexical/package.json b/packages/richtext-lexical/package.json index fc57a62575c..090db524e1b 100644 --- a/packages/richtext-lexical/package.json +++ b/packages/richtext-lexical/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-lexical", - "version": "3.68.5", + "version": "3.69.0", "description": "The officially supported Lexical richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/richtext-slate/package.json b/packages/richtext-slate/package.json index 67d345ebf25..52e833e093e 100644 --- a/packages/richtext-slate/package.json +++ b/packages/richtext-slate/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-slate", - "version": "3.68.5", + "version": "3.69.0", "description": "The officially supported Slate richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index e8d5a2c4fb8..afb834ac638 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/sdk", - "version": "3.68.5", + "version": "3.69.0", "description": "The official Payload REST API SDK", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-azure/package.json b/packages/storage-azure/package.json index e4b18fda951..aebacda135f 100644 --- a/packages/storage-azure/package.json +++ b/packages/storage-azure/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-azure", - "version": "3.68.5", + "version": "3.69.0", "description": "Payload storage adapter for Azure Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-gcs/package.json b/packages/storage-gcs/package.json index e9a538b7de2..e132519e583 100644 --- a/packages/storage-gcs/package.json +++ b/packages/storage-gcs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-gcs", - "version": "3.68.5", + "version": "3.69.0", "description": "Payload storage adapter for Google Cloud Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-r2/package.json b/packages/storage-r2/package.json index 7ac37a9330f..7411b439d55 100644 --- a/packages/storage-r2/package.json +++ b/packages/storage-r2/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-r2", - "version": "3.68.5", + "version": "3.69.0", "description": "Payload storage adapter for Cloudflare R2", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-s3/package.json b/packages/storage-s3/package.json index 6201cca51b7..a8d35f29830 100644 --- a/packages/storage-s3/package.json +++ b/packages/storage-s3/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-s3", - "version": "3.68.5", + "version": "3.69.0", "description": "Payload storage adapter for Amazon S3", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-uploadthing/package.json b/packages/storage-uploadthing/package.json index 377becd094c..88d583c58cf 100644 --- a/packages/storage-uploadthing/package.json +++ b/packages/storage-uploadthing/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-uploadthing", - "version": "3.68.5", + "version": "3.69.0", "description": "Payload storage adapter for uploadthing", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-vercel-blob/package.json b/packages/storage-vercel-blob/package.json index 62ea5a3b692..48d7f235601 100644 --- a/packages/storage-vercel-blob/package.json +++ b/packages/storage-vercel-blob/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-vercel-blob", - "version": "3.68.5", + "version": "3.69.0", "description": "Payload storage adapter for Vercel Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/translations/package.json b/packages/translations/package.json index 1596bc2c54e..2f35c58c42e 100644 --- a/packages/translations/package.json +++ b/packages/translations/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/translations", - "version": "3.68.5", + "version": "3.69.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/ui/package.json b/packages/ui/package.json index cd686664086..71f7784f092 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/ui", - "version": "3.68.5", + "version": "3.69.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", From 4ccc523c907eea97c2581e447b985dd358631082 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Fri, 19 Dec 2025 16:10:23 -0800 Subject: [PATCH 36/67] test: migrate from jest to vitest eslint plugin, remove remaining jest references (#14997) - Removes old references to jest or files/dependencies that were no longer used - Removes the jest eslint plugin - Installs the vitest eslint plugin. Didn't see any issues with the recommended config, scrolling through our test files --- .github/CODEOWNERS | 2 +- package.json | 2 - packages/eslint-config/configs/jest/index.mjs | 10 - .../configs/jest/rules/jest-dom.mjs | 10 - .../eslint-config/configs/jest/rules/jest.mjs | 38 - packages/eslint-config/index.mjs | 23 +- packages/eslint-config/package.json | 3 +- packages/eslint-plugin/package.json | 3 +- .../graphql/src/utilities/formatName.spec.ts | 1 - pnpm-lock.yaml | 1636 +---------------- test/bulk-edit/e2e.spec.ts | 1 - test/eslint.config.js | 10 +- test/fields/collections/Date/e2e.spec.ts | 1 - test/jest-spec-reporter.cjs | 121 -- test/jestreporter.cjs | 16 - 15 files changed, 54 insertions(+), 1823 deletions(-) delete mode 100644 packages/eslint-config/configs/jest/index.mjs delete mode 100644 packages/eslint-config/configs/jest/rules/jest-dom.mjs delete mode 100644 packages/eslint-config/configs/jest/rules/jest.mjs delete mode 100644 test/jest-spec-reporter.cjs delete mode 100644 test/jestreporter.cjs diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 41527dcb2be..50a5cbe8688 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -22,7 +22,7 @@ ## Build Files -**/jest.config.js @denolfe @AlessioGr +**/vitest.config.ts @denolfe @AlessioGr **/tsconfig*.json @denolfe @AlessioGr ## Root diff --git a/package.json b/package.json index 7225bd02a34..96b1d29b63e 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,6 @@ "script:pack": "pnpm --filter scripts pack-all-to-dest", "pretest": "pnpm build", "test": "pnpm test:int && pnpm test:components && pnpm test:e2e", - "test:components": "cross-env NODE_OPTIONS=\" --no-deprecation --no-experimental-strip-types\" jest --config=jest.components.config.js", "test:e2e": "pnpm runts ./test/runE2E.ts", "test:e2e:debug": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 PWDEBUG=1 DISABLE_LOGGING=true playwright test", "test:e2e:headed": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" NODE_NO_WARNINGS=1 DISABLE_LOGGING=true playwright test --headed", @@ -164,7 +163,6 @@ "@swc-node/register": "1.11.1", "@swc/cli": "0.7.9", "@swc/core": "1.15.3", - "@swc/jest": "0.2.39", "@types/fs-extra": "^11.0.2", "@types/minimist": "1.2.5", "@types/node": "22.15.30", diff --git a/packages/eslint-config/configs/jest/index.mjs b/packages/eslint-config/configs/jest/index.mjs deleted file mode 100644 index 88d9b7d3f05..00000000000 --- a/packages/eslint-config/configs/jest/index.mjs +++ /dev/null @@ -1,10 +0,0 @@ -import jestRules from './rules/jest.mjs' -import jestDomRules from './rules/jest-dom.mjs' -import jestDom from 'eslint-plugin-jest-dom' -import jest from 'eslint-plugin-jest' -import { deepMerge } from '../../deepMerge.js' - -/** @type {import('eslint').Linter.Config} */ -export const index = deepMerge({}) - -export default index diff --git a/packages/eslint-config/configs/jest/rules/jest-dom.mjs b/packages/eslint-config/configs/jest/rules/jest-dom.mjs deleted file mode 100644 index f7714a528d7..00000000000 --- a/packages/eslint-config/configs/jest/rules/jest-dom.mjs +++ /dev/null @@ -1,10 +0,0 @@ -/** @type {import('eslint').Linter.Config} */ -export const index = { - 'jest-dom/prefer-checked': 'error', - 'jest-dom/prefer-enabled-disabled': 'error', - 'jest-dom/prefer-focus': 'error', - 'jest-dom/prefer-required': 'error', - 'jest-dom/prefer-to-have-attribute': 'error', -} - -export default index diff --git a/packages/eslint-config/configs/jest/rules/jest.mjs b/packages/eslint-config/configs/jest/rules/jest.mjs deleted file mode 100644 index 0a0c15e0332..00000000000 --- a/packages/eslint-config/configs/jest/rules/jest.mjs +++ /dev/null @@ -1,38 +0,0 @@ -/** @type {import('eslint').Linter.Config} */ -export const index = { - 'jest/consistent-test-it': ['error', { fn: 'it' }], - 'jest/expect-expect': 'error', - 'jest/prefer-lowercase-title': ['error', { ignore: ['describe'] }], - 'jest/no-alias-methods': 'error', - 'jest/no-commented-out-tests': 'off', - 'jest/no-disabled-tests': 'off', - 'jest/no-duplicate-hooks': 'error', - 'jest/no-export': 'error', - 'jest/no-focused-tests': 'error', - 'jest/no-hooks': 'off', - 'jest/no-identical-title': 'error', - 'jest/no-conditional-in-test': 'warn', - 'jest/no-jasmine-globals': 'error', - 'jest/no-large-snapshots': 'error', - 'jest/no-mocks-import': 'error', - 'jest/no-standalone-expect': 'error', - 'jest/no-done-callback': 'error', - 'jest/no-test-prefixes': 'error', - 'jest/no-test-return-statement': 'error', - 'jest/prefer-called-with': 'error', - 'jest/prefer-expect-assertions': 'off', - 'jest/prefer-hooks-on-top': 'error', - 'jest/prefer-spy-on': 'off', // broken in packages/create-payload-app/src/lib/create-project.spec.ts - 'jest/prefer-strict-equal': 'warn', - 'jest/prefer-to-contain': 'error', - 'jest/prefer-to-have-length': 'error', - 'jest/prefer-todo': 'error', - 'jest/require-top-level-describe': 'error', - 'jest/require-to-throw-message': 'error', - 'jest/valid-describe-callback': 'error', - 'jest/valid-expect-in-promise': 'error', - 'jest/valid-expect': 'error', - 'jest/valid-title': 'error', -} - -export default index diff --git a/packages/eslint-config/index.mjs b/packages/eslint-config/index.mjs index 9edeb30b1ee..5676bf1acf3 100644 --- a/packages/eslint-config/index.mjs +++ b/packages/eslint-config/index.mjs @@ -5,12 +5,12 @@ import { configs as regexpPluginConfigs } from 'eslint-plugin-regexp' import eslintConfigPrettier from 'eslint-config-prettier/flat' import payloadPlugin from '@payloadcms/eslint-plugin' import reactExtends from './configs/react/index.mjs' -import jestExtends from './configs/jest/index.mjs' import globals from 'globals' import importX from 'eslint-plugin-import-x' import typescriptParser from '@typescript-eslint/parser' import { deepMerge } from './deepMerge.js' import reactCompiler from 'eslint-plugin-react-compiler' +import vitest from '@vitest/eslint-plugin' const baseRules = { // This rule makes no sense when overriding class methods. This is used a lot in richtext-lexical. @@ -233,17 +233,16 @@ export const rootEslintConfig = [ }, { name: 'Unit Tests', - ...deepMerge(jestExtends, { - plugins: { - payload: payloadPlugin, - }, - rules: { - ...baseRules, - ...typescriptRules, - '@typescript-eslint/unbound-method': 'off', - }, - }), - files: ['**/*.spec.ts'], + plugins: { + vitest + }, + rules: { + ...vitest.configs.recommended.rules, + }, + files: [ + '**/*.spec.ts', + '!**/*.e2e.spec.ts', + ], }, { name: 'Payload Config', diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index 815550c5a4c..c49f338b73e 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -29,11 +29,10 @@ "@payloadcms/eslint-plugin": "workspace:*", "@types/eslint": "9.6.1", "@typescript-eslint/parser": "8.26.1", + "@vitest/eslint-plugin": "1.5.4", "eslint": "9.22.0", "eslint-config-prettier": "10.1.1", "eslint-plugin-import-x": "4.6.1", - "eslint-plugin-jest": "28.11.0", - "eslint-plugin-jest-dom": "5.5.0", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-perfectionist": "3.9.1", "eslint-plugin-react-compiler": "19.1.0-rc.2", diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 50cbec0891f..a7ebfd486ab 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -28,11 +28,10 @@ "@eslint/js": "9.22.0", "@types/eslint": "9.6.1", "@typescript-eslint/parser": "8.26.1", + "@vitest/eslint-plugin": "1.5.4", "eslint": "9.22.0", "eslint-config-prettier": "10.1.1", "eslint-plugin-import-x": "4.6.1", - "eslint-plugin-jest": "28.11.0", - "eslint-plugin-jest-dom": "5.5.0", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-perfectionist": "3.9.1", "eslint-plugin-react-hooks": "0.0.0-experimental-d331ba04-20250307", diff --git a/packages/graphql/src/utilities/formatName.spec.ts b/packages/graphql/src/utilities/formatName.spec.ts index 203b37d2d4c..bfb5b7e4b4a 100644 --- a/packages/graphql/src/utilities/formatName.spec.ts +++ b/packages/graphql/src/utilities/formatName.spec.ts @@ -1,4 +1,3 @@ -/* eslint-disable jest/prefer-strict-equal */ import { describe, it, expect } from 'vitest' import { formatName } from './formatName' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 802598bc2f4..93513912f94 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,9 +56,6 @@ importers: '@swc/core': specifier: 1.15.3 version: 1.15.3 - '@swc/jest': - specifier: 0.2.39 - version: 0.2.39(@swc/core@1.15.3) '@types/fs-extra': specifier: ^11.0.2 version: 11.0.4 @@ -566,6 +563,9 @@ importers: '@typescript-eslint/parser': specifier: 8.26.1 version: 8.26.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) + '@vitest/eslint-plugin': + specifier: 1.5.4 + version: 1.5.4(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3)(vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.15.30)(jiti@2.5.1)(jsdom@26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1)) eslint: specifier: 9.22.0 version: 9.22.0(jiti@2.5.1) @@ -575,12 +575,6 @@ importers: eslint-plugin-import-x: specifier: 4.6.1 version: 4.6.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) - eslint-plugin-jest: - specifier: 28.11.0 - version: 28.11.0(@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(jest@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0))(typescript@5.7.3) - eslint-plugin-jest-dom: - specifier: 5.5.0 - version: 5.5.0(@testing-library/dom@10.4.0)(eslint@9.22.0(jiti@2.5.1)) eslint-plugin-jsx-a11y: specifier: 6.10.2 version: 6.10.2(eslint@9.22.0(jiti@2.5.1)) @@ -620,6 +614,9 @@ importers: '@typescript-eslint/parser': specifier: 8.26.1 version: 8.26.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) + '@vitest/eslint-plugin': + specifier: 1.5.4 + version: 1.5.4(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3)(vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.15.30)(jiti@2.5.1)(jsdom@26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1)) eslint: specifier: 9.22.0 version: 9.22.0(jiti@2.5.1) @@ -629,12 +626,6 @@ importers: eslint-plugin-import-x: specifier: 4.6.1 version: 4.6.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) - eslint-plugin-jest: - specifier: 28.11.0 - version: 28.11.0(@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(jest@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0))(typescript@5.7.3) - eslint-plugin-jest-dom: - specifier: 5.5.0 - version: 5.5.0(@testing-library/dom@10.4.0)(eslint@9.22.0(jiti@2.5.1)) eslint-plugin-jsx-a11y: specifier: 6.10.2 version: 6.10.2(eslint@9.22.0(jiti@2.5.1)) @@ -1859,7 +1850,7 @@ importers: version: 16.8.1 next: specifier: 15.4.10 - version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: workspace:* version: link:../../packages/payload @@ -2001,7 +1992,7 @@ importers: version: 8.6.0(react@19.2.1) geist: specifier: ^1.3.0 - version: 1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.4.2(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) graphql: specifier: 16.8.1 version: 16.8.1 @@ -2013,7 +2004,7 @@ importers: version: 0.477.0(react@19.2.1) next: specifier: 15.4.10 - version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes: specifier: 0.4.6 version: 0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -3472,27 +3463,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-async-generators@7.8.4': - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-bigint@7.8.3': - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-class-properties@7.12.13': - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-class-static-block@7.14.5': - resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.27.1': resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} engines: {node: '>=6.9.0'} @@ -3505,64 +3475,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-meta@7.10.4': - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-json-strings@7.8.3': - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4': - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-numeric-separator@7.10.4': - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-object-rest-spread@7.8.3': - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-optional-catch-binding@7.8.3': - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-optional-chaining@7.8.3': - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-private-property-in-object@7.14.5': - resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-top-level-await@7.14.5': - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.27.1': resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} engines: {node: '>=6.9.0'} @@ -3964,9 +3882,6 @@ packages: resolution: {integrity: sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==} engines: {node: '>=6.9.0'} - '@bcoe/v8-coverage@0.2.3': - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - '@bufbuild/protobuf@2.2.2': resolution: {integrity: sha512-UNtPCbrwrenpmrXuRwn9jYpPoweNXj8X5sMvYgsqYyaH8jQ6LfUJSk3dJLnBK+6sfYPrF4iAIo5sd5HQ+tg75A==} @@ -5300,96 +5215,6 @@ packages: resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} - '@istanbuljs/load-nyc-config@1.1.0': - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} - - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - - '@jest/console@29.7.0': - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/core@29.7.0': - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - - '@jest/create-cache-key-function@30.2.0': - resolution: {integrity: sha512-44F4l4Enf+MirJN8X/NhdGkl71k5rBYiwdVlo4HxOwbu0sHV8QKrGEedb1VUU4K3W7fBKE0HGfbn7eZm0Ti3zg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/environment@29.7.0': - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/expect-utils@29.7.0': - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/expect@29.7.0': - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/fake-timers@29.7.0': - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/globals@29.7.0': - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/pattern@30.0.1': - resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/reporters@29.7.0': - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/schemas@30.0.5': - resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - '@jest/source-map@29.6.3': - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/test-result@29.7.0': - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/test-sequencer@29.7.0': - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/transform@29.7.0': - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/types@29.6.3': - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/types@30.2.0': - resolution: {integrity: sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -6938,12 +6763,6 @@ packages: peerDependencies: webpack: '>=4.40.0' - '@sinclair/typebox@0.27.8': - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - - '@sinclair/typebox@0.34.41': - resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==} - '@sindresorhus/is@5.6.0': resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} engines: {node: '>=14.16'} @@ -6960,12 +6779,6 @@ packages: resolution: {integrity: sha512-5/kmIOY9FF32nicXH+5yLNTX4NJ4atl7jRgqAJuIn/iyDFXBktOKDxCvyGE/EzmF4ngSUvjXxQUQlQiZ5lfw+w==} engines: {node: '>=10'} - '@sinonjs/commons@3.0.1': - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - - '@sinonjs/fake-timers@10.3.0': - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@smithy/abort-controller@2.2.0': resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==} engines: {node: '>=14.0.0'} @@ -7731,12 +7544,6 @@ packages: '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@swc/jest@0.2.39': - resolution: {integrity: sha512-eyokjOwYd0Q8RnMHri+8/FS1HIrIUKK/sRrFp8c1dThUOfNeCWbLmBP1P5VsKdvmkd25JaH+OKYwEYiAYg9YAA==} - engines: {npm: '>= 7.0.0'} - peerDependencies: - '@swc/core': '*' - '@swc/types@0.1.25': resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==} @@ -7973,9 +7780,6 @@ packages: '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} - '@types/graceful-fs@4.1.9': - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -7985,15 +7789,6 @@ packages: '@types/is-hotkey@0.1.10': resolution: {integrity: sha512-RvC8KMw5BCac1NvRRyaHgMMEtBaZ6wh0pyPTBu7izn4Sj/AX9Y4aXU5c7rX8PnM/knsuUpC1IeoBkANtxBypsQ==} - '@types/istanbul-lib-coverage@2.0.6': - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - - '@types/istanbul-lib-report@3.0.3': - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - - '@types/istanbul-reports@3.0.4': - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -8106,9 +7901,6 @@ packages: '@types/shimmer@1.2.0': resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==} - '@types/stack-utils@2.0.3': - resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - '@types/to-snake-case@1.0.0': resolution: {integrity: sha512-9YtLP+wuIL2EwOqyUjwTzWK6CGVnsP13vJ3i0U8S7O+SLAxrsi1jwC2TkHkdqVqfGLQWnk5H+Z+sSPT7SJeGYg==} @@ -8136,12 +7928,6 @@ packages: '@types/ws@8.5.13': resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} - '@types/yargs-parser@21.0.3': - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - - '@types/yargs@17.0.33': - resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - '@typescript-eslint/eslint-plugin@8.26.1': resolution: {integrity: sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -8381,6 +8167,19 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + '@vitest/eslint-plugin@1.5.4': + resolution: {integrity: sha512-usuVvl6zdqIkUgQlodxvvFBR7HIZIjWQqQemnc7ysqEP4jubLsDaaOhiJAwVz8PlrkBJRuHkC6PCux+OcEF6hg==} + engines: {node: '>=18'} + peerDependencies: + eslint: '>=8.57.0' + typescript: 5.7.3 + vitest: '*' + peerDependenciesMeta: + typescript: + optional: true + vitest: + optional: true + '@vitest/expect@3.2.3': resolution: {integrity: sha512-W2RH2TPWVHA1o7UmaFKISPvdicFJH+mjykctJFoAkUw+SPTJTGjUNdKscFBrqM7IPnCVu6zihtKYa7TkZS1dkQ==} @@ -8689,9 +8488,6 @@ packages: arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -8825,20 +8621,6 @@ packages: b4a@1.6.7: resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} - babel-jest@29.7.0: - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 - - babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - - babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} @@ -8866,17 +8648,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - babel-preset-current-node-syntax@1.1.0: - resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} - peerDependencies: - '@babel/core': ^7.0.0 - - babel-preset-jest@29.6.3: - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 - balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -8976,9 +8747,6 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - bson-objectid@2.0.4: resolution: {integrity: sha512-vgnKAUzcDoa+AeyYwXCoHyF2q6u/8H46dxu5JN+4/TZeq/Dlinn0K6GvxsCLb3LHUJl0m/TLiEK31kUwtgocMQ==} @@ -9070,10 +8838,6 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} @@ -9112,10 +8876,6 @@ packages: resolution: {integrity: sha512-cTZXBcJMl3pudE40WENOakXkcVtrbBpbkmSkM20NdRiUqa4+VYRdXdEsgQ0BNQ6JBE2YymTNWtPKVF7UCTN5+g==} hasBin: true - char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} @@ -9154,10 +8914,6 @@ packages: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - ci-info@4.1.0: resolution: {integrity: sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==} engines: {node: '>=8'} @@ -9189,10 +8945,6 @@ packages: cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - cliui@9.0.1: resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} engines: {node: '>=20'} @@ -9208,16 +8960,9 @@ packages: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} - co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - code-block-writer@12.0.0: resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==} - collect-v8-coverage@1.0.2: - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -9356,11 +9101,6 @@ packages: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} - create-jest@29.7.0: - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - croner@9.1.0: resolution: {integrity: sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==} engines: {node: '>=18.0'} @@ -9561,14 +9301,6 @@ packages: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} - dedent@1.5.3: - resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -9658,10 +9390,6 @@ packages: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} - detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - detect-newline@4.0.1: resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -9678,10 +9406,6 @@ packages: didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -9857,10 +9581,6 @@ packages: embla-carousel@8.6.0: resolution: {integrity: sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==} - emittery@0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} - emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -10099,29 +9819,6 @@ packages: '@typescript-eslint/parser': optional: true - eslint-plugin-jest-dom@5.5.0: - resolution: {integrity: sha512-CRlXfchTr7EgC3tDI7MGHY6QjdJU5Vv2RPaeeGtkXUHnKZf04kgzMPIJUXt4qKCvYWVVIEo9ut9Oq1vgXAykEA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6', yarn: '>=1'} - peerDependencies: - '@testing-library/dom': ^8.0.0 || ^9.0.0 || ^10.0.0 - eslint: ^6.8.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - peerDependenciesMeta: - '@testing-library/dom': - optional: true - - eslint-plugin-jest@28.11.0: - resolution: {integrity: sha512-QAfipLcNCWLVocVbZW8GimKn5p5iiMcgGbRzz8z/P5q7xw+cNEpYqyzFMtIF/ZgF2HLOyy+dYBut+DoYolvqig==} - engines: {node: ^16.10.0 || ^18.12.0 || >=20.0.0} - peerDependencies: - '@typescript-eslint/eslint-plugin': ^6.0.0 || ^7.0.0 || ^8.0.0 - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - jest: '*' - peerDependenciesMeta: - '@typescript-eslint/eslint-plugin': - optional: true - jest: - optional: true - eslint-plugin-jsx-a11y@6.10.2: resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} engines: {node: '>=4.0'} @@ -10361,10 +10058,6 @@ packages: resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} engines: {node: '>=6'} - exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} - engines: {node: '>= 0.8.0'} - expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} @@ -10381,10 +10074,6 @@ packages: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} - expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - express-rate-limit@7.5.1: resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} engines: {node: '>= 16'} @@ -10464,9 +10153,6 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - fdir@6.4.2: resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} peerDependencies: @@ -10715,10 +10401,6 @@ packages: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} - get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -11039,11 +10721,6 @@ packages: import-in-the-middle@1.11.2: resolution: {integrity: sha512-gK6Rr6EykBcc6cVWRSBR5TWf8nn6hZMYSRYqCcHa0l0d1fPK7JSYo6+Mlmck76jIX9aL/IZ71c06U2VpFwl1zA==} - import-local@3.2.0: - resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} - engines: {node: '>=8'} - hasBin: true - imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -11198,10 +10875,6 @@ packages: resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} engines: {node: '>=18'} - is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} - is-generator-function@1.1.0: resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} engines: {node: '>= 0.4'} @@ -11370,30 +11043,6 @@ packages: isomorphic.js@0.2.5: resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - - istanbul-lib-instrument@6.0.3: - resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} - engines: {node: '>=10'} - - istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} - - istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - - istanbul-reports@3.1.7: - resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} - engines: {node: '>=8'} - iterator.prototype@1.1.5: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} @@ -11405,143 +11054,10 @@ packages: resolution: {integrity: sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==} engines: {node: 20 || >=22} - jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-cli@29.7.0: - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - - jest-config@29.7.0: - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - - jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-pnp-resolver@1.2.3: - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - - jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-regex-util@30.0.1: - resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - - jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-worker@27.5.1: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} - jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest@29.7.0: - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - jiti@1.21.6: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true @@ -11572,10 +11088,6 @@ packages: js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -11637,9 +11149,6 @@ packages: engines: {node: '>=6'} hasBin: true - jsonc-parser@3.3.1: - resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} - jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} @@ -11697,10 +11206,6 @@ packages: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} - leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -11918,9 +11423,6 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -12367,9 +11869,6 @@ packages: resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==} hasBin: true - node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} @@ -12964,10 +12463,6 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - prism-react-renderer@2.4.1: resolution: {integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==} peerDependencies: @@ -13296,20 +12791,12 @@ packages: resolution: {integrity: sha512-X34iHADNbNDfr6OTStIAHWSAvvKQRYgLO6duASaVf7J2VA3lvmNYboAHOuLC2huav1IwgZJtyEcJCKVzFxOSMQ==} engines: {node: '>=8.6.0'} - requireindex@1.2.0: - resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} - engines: {node: '>=0.10.5'} - reselect@5.1.1: resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - resolve-dir@1.0.1: resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} engines: {node: '>=0.10.0'} @@ -13318,17 +12805,9 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve.exports@2.0.2: - resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} - engines: {node: '>=10'} - resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -13837,9 +13316,6 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} - source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -13883,9 +13359,6 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} @@ -13898,10 +13371,6 @@ packages: stable-hash@0.0.5: resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} - stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -13959,10 +13428,6 @@ packages: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} - string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} - string-ts@2.2.1: resolution: {integrity: sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==} @@ -14032,10 +13497,6 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - strip-dirs@3.0.0: resolution: {integrity: sha512-I0sdgcFTfKQlUPZyAqPJmSG3HLO9rWDFnxonnIbskYNM3DwFOeTNB5KzVq3dA1GdRAc/25b5Y7UO2TQfKWw4aQ==} @@ -14237,10 +13698,6 @@ packages: engines: {node: '>=10'} hasBin: true - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - text-decoder@1.2.1: resolution: {integrity: sha512-x9v3H/lTKIJKQQe7RPQkLfKAnc9lUTkWDypIQgTzPJAq+5/GCDHonmshfvlsNSj58yyshbIJJDLmU15qNERrXQ==} @@ -14314,9 +13771,6 @@ packages: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true - tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - to-no-case@1.0.2: resolution: {integrity: sha512-Z3g735FxuZY8rodxV4gH7LxClE4H0hTIyHNIHdk+vpQxjLm0cwnKXq/OFVZ76SOQmto7txVcwSCwkU5kqp+FKg==} @@ -14487,10 +13941,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - type-fest@0.16.0: resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} engines: {node: '>=10'} @@ -14766,10 +14216,6 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - v8-to-istanbul@9.3.0: - resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} - engines: {node: '>=10.12.0'} - validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -14917,9 +14363,6 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} - walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - watchpack@2.4.2: resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} engines: {node: '>=10.13.0'} @@ -15056,10 +14499,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - ws@7.5.10: resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} engines: {node: '>=8.3.0'} @@ -15137,10 +14576,6 @@ packages: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - yargs-parser@22.0.0: resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} engines: {node: ^20.19.0 || ^22.12.0 || >=23} @@ -15149,10 +14584,6 @@ packages: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - yargs@18.0.0: resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} engines: {node: ^20.19.0 || ^22.12.0 || >=23} @@ -17219,105 +16650,21 @@ snapshots: dependencies: '@babel/core': 7.27.3 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.27.3)': + '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 - optional: true - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.27.3)': + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.3)': - dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - optional: true - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.3)': dependencies: '@babel/core': 7.27.3 @@ -17847,9 +17194,6 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@bcoe/v8-coverage@0.2.3': - optional: true - '@bufbuild/protobuf@2.2.2': {} '@clack/core@0.3.4': @@ -18893,217 +18237,6 @@ snapshots: dependencies: minipass: 7.1.2 - '@istanbuljs/load-nyc-config@1.1.0': - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 3.14.1 - resolve-from: 5.0.0 - optional: true - - '@istanbuljs/schema@0.1.3': - optional: true - - '@jest/console@29.7.0': - dependencies: - '@jest/types': 29.6.3 - '@types/node': 22.15.30 - chalk: 4.1.2 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - slash: 3.0.0 - optional: true - - '@jest/core@29.7.0(babel-plugin-macros@3.1.0)': - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.15.30 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - optional: true - - '@jest/create-cache-key-function@30.2.0': - dependencies: - '@jest/types': 30.2.0 - - '@jest/environment@29.7.0': - dependencies: - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.15.30 - jest-mock: 29.7.0 - optional: true - - '@jest/expect-utils@29.7.0': - dependencies: - jest-get-type: 29.6.3 - optional: true - - '@jest/expect@29.7.0': - dependencies: - expect: 29.7.0 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - optional: true - - '@jest/fake-timers@29.7.0': - dependencies: - '@jest/types': 29.6.3 - '@sinonjs/fake-timers': 10.3.0 - '@types/node': 22.15.30 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-util: 29.7.0 - optional: true - - '@jest/globals@29.7.0': - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/types': 29.6.3 - jest-mock: 29.7.0 - transitivePeerDependencies: - - supports-color - optional: true - - '@jest/pattern@30.0.1': - dependencies: - '@types/node': 22.15.30 - jest-regex-util: 30.0.1 - - '@jest/reporters@29.7.0': - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 22.15.30 - chalk: 4.1.2 - collect-v8-coverage: 1.0.2 - exit: 0.1.2 - glob: 7.2.3 - graceful-fs: 4.2.11 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 6.0.3 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.7 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - jest-worker: 29.7.0 - slash: 3.0.0 - string-length: 4.0.2 - strip-ansi: 6.0.1 - v8-to-istanbul: 9.3.0 - transitivePeerDependencies: - - supports-color - optional: true - - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.8 - optional: true - - '@jest/schemas@30.0.5': - dependencies: - '@sinclair/typebox': 0.34.41 - - '@jest/source-map@29.6.3': - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - callsites: 3.1.0 - graceful-fs: 4.2.11 - optional: true - - '@jest/test-result@29.7.0': - dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.2 - optional: true - - '@jest/test-sequencer@29.7.0': - dependencies: - '@jest/test-result': 29.7.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - slash: 3.0.0 - optional: true - - '@jest/transform@29.7.0': - dependencies: - '@babel/core': 7.27.3 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.8 - pirates: 4.0.7 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - optional: true - - '@jest/types@29.6.3': - dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 22.15.30 - '@types/yargs': 17.0.33 - chalk: 4.1.2 - optional: true - - '@jest/types@30.2.0': - dependencies: - '@jest/pattern': 30.0.1 - '@jest/schemas': 30.0.5 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 22.15.30 - '@types/yargs': 17.0.33 - chalk: 4.1.2 - '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -20827,11 +19960,6 @@ snapshots: - encoding - supports-color - '@sinclair/typebox@0.27.8': - optional: true - - '@sinclair/typebox@0.34.41': {} - '@sindresorhus/is@5.6.0': {} '@sindresorhus/is@7.1.0': {} @@ -20846,16 +19974,6 @@ snapshots: escape-string-regexp: 2.0.0 lodash.deburr: 4.1.0 - '@sinonjs/commons@3.0.1': - dependencies: - type-detect: 4.0.8 - optional: true - - '@sinonjs/fake-timers@10.3.0': - dependencies: - '@sinonjs/commons': 3.0.1 - optional: true - '@smithy/abort-controller@2.2.0': dependencies: '@smithy/types': 2.12.0 @@ -22001,13 +21119,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@swc/jest@0.2.39(@swc/core@1.15.3)': - dependencies: - '@jest/create-cache-key-function': 30.2.0 - '@swc/core': 1.15.3 - '@swc/counter': 0.1.3 - jsonc-parser: 3.3.1 - '@swc/types@0.1.25': dependencies: '@swc/counter': 0.1.3 @@ -22261,11 +21372,6 @@ snapshots: '@types/minimatch': 5.1.2 '@types/node': 22.15.30 - '@types/graceful-fs@4.1.9': - dependencies: - '@types/node': 22.15.30 - optional: true - '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -22274,16 +21380,6 @@ snapshots: '@types/is-hotkey@0.1.10': {} - '@types/istanbul-lib-coverage@2.0.6': {} - - '@types/istanbul-lib-report@3.0.3': - dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - - '@types/istanbul-reports@3.0.4': - dependencies: - '@types/istanbul-lib-report': 3.0.3 - '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -22428,9 +21524,6 @@ snapshots: '@types/shimmer@1.2.0': {} - '@types/stack-utils@2.0.3': - optional: true - '@types/to-snake-case@1.0.0': {} '@types/tough-cookie@4.0.5': {} @@ -22453,12 +21546,6 @@ snapshots: dependencies: '@types/node': 22.15.30 - '@types/yargs-parser@21.0.3': {} - - '@types/yargs@17.0.33': - dependencies: - '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -22740,6 +21827,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/eslint-plugin@1.5.4(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3)(vitest@4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.15.30)(jiti@2.5.1)(jsdom@26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1))': + dependencies: + '@typescript-eslint/scope-manager': 8.46.2 + '@typescript-eslint/utils': 8.46.2(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) + eslint: 9.22.0(jiti@2.5.1) + optionalDependencies: + typescript: 5.7.3 + vitest: 4.0.15(@opentelemetry/api@1.9.0)(@types/node@22.15.30)(jiti@2.5.1)(jsdom@26.1.0(bufferutil@4.0.8)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass-embedded@1.80.6)(sass@1.77.4)(terser@5.36.0)(tsx@4.20.6)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + '@vitest/expect@3.2.3': dependencies: '@types/chai': 5.2.2 @@ -23160,11 +22258,6 @@ snapshots: arg@5.0.2: {} - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - optional: true - argparse@2.0.1: {} aria-hidden@1.2.6: @@ -23319,39 +22412,6 @@ snapshots: b4a@1.6.7: {} - babel-jest@29.7.0(@babel/core@7.27.3): - dependencies: - '@babel/core': 7.27.3 - '@jest/transform': 29.7.0 - '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.27.3) - chalk: 4.1.2 - graceful-fs: 4.2.11 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - optional: true - - babel-plugin-istanbul@6.1.1: - dependencies: - '@babel/helper-plugin-utils': 7.27.1 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - optional: true - - babel-plugin-jest-hoist@29.6.3: - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.27.3 - '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.20.6 - optional: true - babel-plugin-macros@3.1.0: dependencies: '@babel/runtime': 7.26.0 @@ -23390,33 +22450,6 @@ snapshots: dependencies: '@babel/core': 7.27.3 - babel-preset-current-node-syntax@1.1.0(@babel/core@7.27.3): - dependencies: - '@babel/core': 7.27.3 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.27.3) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.27.3) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.27.3) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.27.3) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.27.3) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.27.3) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.27.3) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.27.3) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.27.3) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.27.3) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.27.3) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.27.3) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.27.3) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.27.3) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.27.3) - optional: true - - babel-preset-jest@29.6.3(@babel/core@7.27.3): - dependencies: - '@babel/core': 7.27.3 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.3) - optional: true - balanced-match@1.0.2: {} bare-events@2.5.0: @@ -23528,11 +22561,6 @@ snapshots: node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.0) - bser@2.1.1: - dependencies: - node-int64: 0.4.0 - optional: true - bson-objectid@2.0.4: {} bson@6.10.4: {} @@ -23637,9 +22665,6 @@ snapshots: camelcase-css@2.0.1: {} - camelcase@5.3.1: - optional: true - camelcase@6.3.0: {} caniuse-lite@1.0.30001720: {} @@ -23693,9 +22718,6 @@ snapshots: transitivePeerDependencies: - magicast - char-regex@1.0.2: - optional: true - character-entities-html4@2.1.0: {} character-entities-legacy@3.0.0: {} @@ -23728,9 +22750,6 @@ snapshots: chrome-trace-event@1.0.4: {} - ci-info@3.9.0: - optional: true - ci-info@4.1.0: {} citty@0.1.6: @@ -23762,13 +22781,6 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - optional: true - cliui@9.0.1: dependencies: string-width: 7.2.0 @@ -23791,14 +22803,8 @@ snapshots: cluster-key-slot@1.1.2: {} - co@4.6.0: - optional: true - code-block-writer@12.0.0: {} - collect-v8-coverage@1.0.2: - optional: true - color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -23920,22 +22926,6 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 - create-jest@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - optional: true - croner@9.1.0: {} cross-env@7.0.3: @@ -24100,11 +23090,6 @@ snapshots: dependencies: mimic-response: 3.1.0 - dedent@1.5.3(babel-plugin-macros@3.1.0): - optionalDependencies: - babel-plugin-macros: 3.1.0 - optional: true - deep-eql@5.0.2: {} deep-extend@0.6.0: {} @@ -24171,9 +23156,6 @@ snapshots: detect-libc@2.0.4: {} - detect-newline@3.1.0: - optional: true - detect-newline@4.0.1: {} detect-node-es@1.1.0: {} @@ -24189,9 +23171,6 @@ snapshots: didyoumean@1.2.2: {} - diff-sequences@29.6.3: - optional: true - dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -24302,9 +23281,6 @@ snapshots: embla-carousel@8.6.0: {} - emittery@0.13.1: - optional: true - emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} @@ -24786,25 +23762,6 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest-dom@5.5.0(@testing-library/dom@10.4.0)(eslint@9.22.0(jiti@2.5.1)): - dependencies: - '@babel/runtime': 7.26.0 - eslint: 9.22.0(jiti@2.5.1) - requireindex: 1.2.0 - optionalDependencies: - '@testing-library/dom': 10.4.0 - - eslint-plugin-jest@28.11.0(@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(jest@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0))(typescript@5.7.3): - dependencies: - '@typescript-eslint/utils': 8.46.2(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) - eslint: 9.22.0(jiti@2.5.1) - optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3))(eslint@9.22.0(jiti@2.5.1))(typescript@5.7.3) - jest: 29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0) - transitivePeerDependencies: - - supports-color - - typescript - eslint-plugin-jsx-a11y@6.10.2(eslint@9.22.0(jiti@2.5.1)): dependencies: aria-query: 5.3.2 @@ -25161,9 +24118,6 @@ snapshots: exit-hook@2.2.1: {} - exit@0.1.2: - optional: true - expand-template@2.0.3: {} expand-tilde@2.0.2: @@ -25174,15 +24128,6 @@ snapshots: expect-type@1.2.2: {} - expect@29.7.0: - dependencies: - '@jest/expect-utils': 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - optional: true - express-rate-limit@7.5.1(express@5.0.1): dependencies: express: 5.0.1 @@ -25293,11 +24238,6 @@ snapshots: dependencies: reusify: 1.0.4 - fb-watchman@2.0.2: - dependencies: - bser: 2.1.1 - optional: true - fdir@6.4.2(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 @@ -25524,6 +24464,10 @@ snapshots: - encoding - supports-color + geist@1.4.2(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + dependencies: + next: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + geist@1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) @@ -25571,9 +24515,6 @@ snapshots: get-nonce@1.0.1: {} - get-package-type@0.1.0: - optional: true - get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -25928,12 +24869,6 @@ snapshots: cjs-module-lexer: 1.4.1 module-details-from-path: 1.0.3 - import-local@3.2.0: - dependencies: - pkg-dir: 4.2.0 - resolve-cwd: 3.0.0 - optional: true - imurmurhash@0.1.4: {} indent-string@4.0.0: {} @@ -26090,9 +25025,6 @@ snapshots: dependencies: get-east-asian-width: 1.3.0 - is-generator-fn@2.1.0: - optional: true - is-generator-function@1.1.0: dependencies: call-bound: 1.0.4 @@ -26238,53 +25170,6 @@ snapshots: isomorphic.js@0.2.5: {} - istanbul-lib-coverage@3.2.2: - optional: true - - istanbul-lib-instrument@5.2.1: - dependencies: - '@babel/core': 7.27.3 - '@babel/parser': 7.27.5 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - optional: true - - istanbul-lib-instrument@6.0.3: - dependencies: - '@babel/core': 7.27.3 - '@babel/parser': 7.27.5 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 7.7.2 - transitivePeerDependencies: - - supports-color - optional: true - - istanbul-lib-report@3.0.1: - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - optional: true - - istanbul-lib-source-maps@4.0.1: - dependencies: - debug: 4.4.3 - istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - optional: true - - istanbul-reports@3.1.7: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - optional: true - iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 @@ -26304,348 +25189,12 @@ snapshots: dependencies: '@isaacs/cliui': 8.0.2 - jest-changed-files@29.7.0: - dependencies: - execa: 5.1.1 - jest-util: 29.7.0 - p-limit: 3.1.0 - optional: true - - jest-circus@29.7.0(babel-plugin-macros@3.1.0): - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.15.30 - chalk: 4.1.2 - co: 4.6.0 - dedent: 1.5.3(babel-plugin-macros@3.1.0) - is-generator-fn: 2.1.0 - jest-each: 29.7.0 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - p-limit: 3.1.0 - pretty-format: 29.7.0 - pure-rand: 6.1.0 - slash: 3.0.0 - stack-utils: 2.0.6 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - optional: true - - jest-cli@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0): - dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0) - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - optional: true - - jest-config@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0): - dependencies: - '@babel/core': 7.27.3 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.27.3) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0(babel-plugin-macros@3.1.0) - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 22.15.30 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - optional: true - - jest-diff@29.7.0: - dependencies: - chalk: 4.1.2 - diff-sequences: 29.6.3 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - optional: true - - jest-docblock@29.7.0: - dependencies: - detect-newline: 3.1.0 - optional: true - - jest-each@29.7.0: - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - jest-get-type: 29.6.3 - jest-util: 29.7.0 - pretty-format: 29.7.0 - optional: true - - jest-environment-node@29.7.0: - dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.15.30 - jest-mock: 29.7.0 - jest-util: 29.7.0 - optional: true - - jest-get-type@29.6.3: - optional: true - - jest-haste-map@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.9 - '@types/node': 22.15.30 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.8 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 - optional: true - - jest-leak-detector@29.7.0: - dependencies: - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - optional: true - - jest-matcher-utils@29.7.0: - dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - optional: true - - jest-message-util@29.7.0: - dependencies: - '@babel/code-frame': 7.27.1 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.3 - chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - stack-utils: 2.0.6 - optional: true - - jest-mock@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/node': 22.15.30 - jest-util: 29.7.0 - optional: true - - jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - optionalDependencies: - jest-resolve: 29.7.0 - optional: true - - jest-regex-util@29.6.3: - optional: true - - jest-regex-util@30.0.1: {} - - jest-resolve-dependencies@29.7.0: - dependencies: - jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - optional: true - - jest-resolve@29.7.0: - dependencies: - chalk: 4.1.2 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.8 - resolve.exports: 2.0.2 - slash: 3.0.0 - optional: true - - jest-runner@29.7.0: - dependencies: - '@jest/console': 29.7.0 - '@jest/environment': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.15.30 - chalk: 4.1.2 - emittery: 0.13.1 - graceful-fs: 4.2.11 - jest-docblock: 29.7.0 - jest-environment-node: 29.7.0 - jest-haste-map: 29.7.0 - jest-leak-detector: 29.7.0 - jest-message-util: 29.7.0 - jest-resolve: 29.7.0 - jest-runtime: 29.7.0 - jest-util: 29.7.0 - jest-watcher: 29.7.0 - jest-worker: 29.7.0 - p-limit: 3.1.0 - source-map-support: 0.5.13 - transitivePeerDependencies: - - supports-color - optional: true - - jest-runtime@29.7.0: - dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/globals': 29.7.0 - '@jest/source-map': 29.6.3 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.15.30 - chalk: 4.1.2 - cjs-module-lexer: 1.4.1 - collect-v8-coverage: 1.0.2 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - slash: 3.0.0 - strip-bom: 4.0.0 - transitivePeerDependencies: - - supports-color - optional: true - - jest-snapshot@29.7.0: - dependencies: - '@babel/core': 7.27.3 - '@babel/generator': 7.27.5 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.3) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.3) - '@babel/types': 7.27.3 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.3) - chalk: 4.1.2 - expect: 29.7.0 - graceful-fs: 4.2.11 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - natural-compare: 1.4.0 - pretty-format: 29.7.0 - semver: 7.7.2 - transitivePeerDependencies: - - supports-color - optional: true - - jest-util@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/node': 22.15.30 - chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - optional: true - - jest-validate@29.7.0: - dependencies: - '@jest/types': 29.6.3 - camelcase: 6.3.0 - chalk: 4.1.2 - jest-get-type: 29.6.3 - leven: 3.1.0 - pretty-format: 29.7.0 - optional: true - - jest-watcher@29.7.0: - dependencies: - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 22.15.30 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - emittery: 0.13.1 - jest-util: 29.7.0 - string-length: 4.0.2 - optional: true - jest-worker@27.5.1: dependencies: '@types/node': 22.15.30 merge-stream: 2.0.0 supports-color: 8.1.1 - jest-worker@29.7.0: - dependencies: - '@types/node': 22.15.30 - jest-util: 29.7.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - optional: true - - jest@29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0): - dependencies: - '@jest/core': 29.7.0(babel-plugin-macros@3.1.0) - '@jest/types': 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.15.30)(babel-plugin-macros@3.1.0) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - optional: true - jiti@1.21.6: {} jiti@2.5.1: {} @@ -26664,12 +25213,6 @@ snapshots: js-tokens@9.0.1: {} - js-yaml@3.14.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - optional: true - js-yaml@4.1.0: dependencies: argparse: 2.0.1 @@ -26742,8 +25285,6 @@ snapshots: json5@2.2.3: {} - jsonc-parser@3.3.1: {} - jsonfile@6.1.0: dependencies: universalify: 2.0.1 @@ -26808,9 +25349,6 @@ snapshots: dependencies: language-subtag-registry: 0.3.23 - leven@3.1.0: - optional: true - levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -27026,11 +25564,6 @@ snapshots: dependencies: semver: 7.7.2 - makeerror@1.0.12: - dependencies: - tmpl: 1.0.5 - optional: true - math-intrinsics@1.1.0: {} mcp-handler@1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): @@ -27683,9 +26216,6 @@ snapshots: node-gyp-build@4.8.2: {} - node-int64@0.4.0: - optional: true - node-releases@2.0.18: {} node-releases@2.0.19: {} @@ -28234,13 +26764,6 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - optional: true - prism-react-renderer@2.4.1(react@19.2.1): dependencies: '@types/prismjs': 1.26.5 @@ -28623,17 +27146,10 @@ snapshots: transitivePeerDependencies: - supports-color - requireindex@1.2.0: {} - reselect@5.1.1: {} resolve-alpn@1.2.1: {} - resolve-cwd@3.0.0: - dependencies: - resolve-from: 5.0.0 - optional: true - resolve-dir@1.0.1: dependencies: expand-tilde: 2.0.2 @@ -28641,14 +27157,8 @@ snapshots: resolve-from@4.0.0: {} - resolve-from@5.0.0: - optional: true - resolve-pkg-maps@1.0.0: {} - resolve.exports@2.0.2: - optional: true - resolve@1.22.8: dependencies: is-core-module: 2.15.1 @@ -29272,12 +27782,6 @@ snapshots: source-map-js@1.2.1: {} - source-map-support@0.5.13: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - optional: true - source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 @@ -29323,9 +27827,6 @@ snapshots: split2@4.2.0: {} - sprintf-js@1.0.3: - optional: true - sprintf-js@1.1.3: optional: true @@ -29335,11 +27836,6 @@ snapshots: stable-hash@0.0.5: {} - stack-utils@2.0.6: - dependencies: - escape-string-regexp: 2.0.0 - optional: true - stackback@0.0.2: {} stacktrace-parser@0.1.10: @@ -29396,12 +27892,6 @@ snapshots: string-argv@0.3.2: {} - string-length@4.0.2: - dependencies: - char-regex: 1.0.2 - strip-ansi: 6.0.1 - optional: true - string-ts@2.2.1: {} string-width@4.2.3: @@ -29510,9 +28000,6 @@ snapshots: strip-bom@3.0.0: {} - strip-bom@4.0.0: - optional: true - strip-dirs@3.0.0: dependencies: inspect-with-kind: 1.0.5 @@ -29761,13 +28248,6 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - test-exclude@6.0.0: - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - optional: true - text-decoder@1.2.1: {} thenify-all@1.6.0: @@ -29830,9 +28310,6 @@ snapshots: dependencies: tldts-core: 6.1.86 - tmpl@1.0.5: - optional: true - to-no-case@1.0.2: {} to-regex-range@5.0.1: @@ -29978,9 +28455,6 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-detect@4.0.8: - optional: true - type-fest@0.16.0: {} type-fest@0.21.3: {} @@ -30275,13 +28749,6 @@ snapshots: uuid@9.0.1: {} - v8-to-istanbul@9.3.0: - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - '@types/istanbul-lib-coverage': 2.0.6 - convert-source-map: 2.0.0 - optional: true - validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 @@ -30616,11 +29083,6 @@ snapshots: dependencies: xml-name-validator: 5.0.0 - walker@1.0.8: - dependencies: - makeerror: 1.0.12 - optional: true - watchpack@2.4.2: dependencies: glob-to-regexp: 0.4.1 @@ -30828,12 +29290,6 @@ snapshots: wrappy@1.0.2: {} - write-file-atomic@4.0.2: - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - optional: true - ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.5): optionalDependencies: bufferutil: 4.0.8 @@ -30873,9 +29329,6 @@ snapshots: yargs-parser@20.2.9: {} - yargs-parser@21.1.1: - optional: true - yargs-parser@22.0.0: {} yargs@16.2.0: @@ -30888,17 +29341,6 @@ snapshots: y18n: 5.0.8 yargs-parser: 20.2.9 - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - optional: true - yargs@18.0.0: dependencies: cliui: 9.0.1 diff --git a/test/bulk-edit/e2e.spec.ts b/test/bulk-edit/e2e.spec.ts index 4f09d51ad47..d9b9986d1dd 100644 --- a/test/bulk-edit/e2e.spec.ts +++ b/test/bulk-edit/e2e.spec.ts @@ -75,7 +75,6 @@ test.describe('Bulk Edit', () => { // Deselect the first row await page.locator('.row-1 input').click() - // eslint-disable-next-line jest-dom/prefer-checked await expect(page.locator('input#select-all')).not.toHaveAttribute('checked', '') }) diff --git a/test/eslint.config.js b/test/eslint.config.js index 6da57727301..bef37012cde 100644 --- a/test/eslint.config.js +++ b/test/eslint.config.js @@ -8,7 +8,7 @@ import playwright from 'eslint-plugin-playwright' export const testEslintConfig = [ ...rootEslintConfig, { - ignores: [...defaultESLintIgnores, '**/payload-types.ts', 'jest.setup.js'], + ignores: [...defaultESLintIgnores, '**/payload-types.ts'], }, { rules: { @@ -38,7 +38,6 @@ export const testEslintConfig = [ files: ['**/*.int.spec.ts', '**/int.spec.ts'], rules: { '@typescript-eslint/no-explicit-any': 'off', - 'jest/prefer-strict-equal': 'off', }, }, { @@ -51,12 +50,6 @@ export const testEslintConfig = [ 'payload/no-relative-monorepo-imports': 'error', '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/no-use-before-define': 'off', - 'jest/consistent-test-it': 'off', - 'jest/expect-expect': 'off', - 'jest/no-test-callback': 'off', - 'jest/prefer-strict-equal': 'off', - 'jest/require-top-level-describe': 'off', - 'jest-dom/prefer-to-have-attribute': 'off', 'playwright/prefer-web-first-assertions': 'error', 'payload/no-flaky-assertions': 'warn', 'payload/no-wait-function': 'warn', @@ -88,7 +81,6 @@ export const testEslintConfig = [ 'payload/no-relative-monorepo-imports': 'error', '@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/no-use-before-define': 'off', - 'jest/expect-expect': 'off', }, }, ] diff --git a/test/fields/collections/Date/e2e.spec.ts b/test/fields/collections/Date/e2e.spec.ts index 3917efe1b2f..4727a4e7fd9 100644 --- a/test/fields/collections/Date/e2e.spec.ts +++ b/test/fields/collections/Date/e2e.spec.ts @@ -544,7 +544,6 @@ describe('Date', () => { ) await expect(dateFieldRequiredOnlyTz).toBeVisible() - // eslint-disable-next-line jest-dom/prefer-required await expect(dateFieldRequiredOnlyTz).not.toHaveAttribute('required') const timezoneClearButtonOnlyTz = page.locator( diff --git a/test/jest-spec-reporter.cjs b/test/jest-spec-reporter.cjs deleted file mode 100644 index 7fd2d02d116..00000000000 --- a/test/jest-spec-reporter.cjs +++ /dev/null @@ -1,121 +0,0 @@ -// From https://github.com/robertbradleyux/jest-ci-spec-reporter/blob/main/src/jest-ci-spec-reporter.ts -/* -MIT License - -Copyright (c) 2023 Robert Bradley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ -'use strict' -Object.defineProperty(exports, '__esModule', { value: true }) -class JestCiSpecReporter { - onRunStart({ numTotalTestSuites }) { - console.log() - console.log(`Found ${numTotalTestSuites} test suites.`) - console.log() - } - onRunComplete(_, results) { - const { - numFailedTests, - numPassedTests, - numPendingTests, - testResults, - numTotalTests, - startTime, - } = results - testResults.forEach(({ failureMessage }) => { - if (failureMessage) { - console.log(failureMessage) - } - }) - const testResultText = numFailedTests === 0 ? 'SUCCESS' : 'FAILED' - const numNotSkippedTests = numPassedTests + numFailedTests - const runDuration = this._getRunDuration(startTime) - console.log() - console.log( - `Executed ${numNotSkippedTests} of ${numTotalTests} (skipped ${numPendingTests}) ${testResultText} (${runDuration})`, - ) - console.log(`TOTAL: ${numFailedTests || numNotSkippedTests} ${testResultText}`) - } - onTestResult(test, { testResults }) { - // Log pretty ALL RESULTS message - console.log('\n\n\x1b[1m\x1b[30mALL RESULTS\x1b[0m') - testResults.forEach((result) => { - var _a, _b - const { title, duration, status, ancestorTitles } = result - const { name } = - (_b = (_a = test.context.config) === null || _a === void 0 ? void 0 : _a.displayName) !== - null && _b !== void 0 - ? _b - : {} - if (name) { - ancestorTitles.unshift(name) - } - const breadcrumbs = `${ancestorTitles.join(' > ')} >` - - console.log( - ` ${this._getTestStatus(status)} ${breadcrumbs} ${title} ${this._getTestDuration(duration)}`, - ) - }) - } - - onTestCaseResult(test, result) { - var _a, _b - const { title, duration, status, ancestorTitles } = result - const { name } = - (_b = (_a = test.context.config) === null || _a === void 0 ? void 0 : _a.displayName) !== - null && _b !== void 0 - ? _b - : {} - if (name) { - ancestorTitles.unshift(name) - } - const breadcrumbs = `${ancestorTitles.join(' > ')} >` - - console.log( - ` ${this._getTestStatus(status)} ${breadcrumbs} ${title} ${this._getTestDuration(duration)}`, - ) - } - - getLastError() { - return undefined - } - _getRunDuration(startTime) { - const deltaInMillis = new Date().getTime() - new Date(startTime).getTime() - const seconds = ((deltaInMillis % 60000) / 1000).toFixed(3) - return `${seconds} secs` - } - _getTestDuration(duration) { - return `\x1b[1m\x1b[30m(${duration !== null && duration !== void 0 ? duration : 0}ms)\x1b[0m` - } - _getTestStatus(status) { - switch (status) { - case 'passed': - return '\x1b[1m\x1b[32m[PASS]\x1b[0m' - case 'pending': - return '\x1b[1m\x1b[33m[SKIP]\x1b[0m' - case 'todo': - return '\x1b[1m\x1b[34m[TODO]\x1b[0m' - case 'failed': - default: - return '\x1b[1m\x1b[31m[FAIL]\x1b[0m' - } - } -} -exports.default = JestCiSpecReporter diff --git a/test/jestreporter.cjs b/test/jestreporter.cjs deleted file mode 100644 index 6eac18a61ad..00000000000 --- a/test/jestreporter.cjs +++ /dev/null @@ -1,16 +0,0 @@ -class CustomReporter { - constructor(globalConfig, reporterOptions, reporterContext) { - this._globalConfig = globalConfig - this._options = reporterOptions - this._context = reporterContext - } - - onTestCaseResult(test, testCaseResult) { - if (testCaseResult.status === 'passed') { - return - } - console.log('Test case result:', testCaseResult) - } -} - -module.exports = CustomReporter From e0119f36c428320c1ee076fc43ff047315eec9f5 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Fri, 19 Dec 2025 19:08:17 -0800 Subject: [PATCH 37/67] chore: narrow down files affected by vitest lint rules (#15000) The previous glob pattern was incorrect and caused _all_ files to be included, which is not what we want. The new config entry uses `ignores` to ensure all .spec.ts that are **not** .e2e.spec.ts files are targeted. --- packages/eslint-config/index.mjs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/eslint-config/index.mjs b/packages/eslint-config/index.mjs index 5676bf1acf3..9a82716f96b 100644 --- a/packages/eslint-config/index.mjs +++ b/packages/eslint-config/index.mjs @@ -232,17 +232,15 @@ export const rootEslintConfig = [ files: ['**/*.tsx'], }, { - name: 'Unit Tests', + name: 'Unit and Integration Tests', plugins: { - vitest + vitest, }, rules: { ...vitest.configs.recommended.rules, }, - files: [ - '**/*.spec.ts', - '!**/*.e2e.spec.ts', - ], + files: ['**/*.spec.ts'], + ignores: ['**/*.e2e.spec.ts'], }, { name: 'Payload Config', @@ -257,6 +255,7 @@ export const rootEslintConfig = [ { name: 'React Compiler', ...reactCompiler.configs.recommended, + files: ['**/*.tsx'], }, ] From 562ec16dca13eecd2b79427b2fe42914893f3b77 Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Fri, 19 Dec 2025 22:09:00 -0500 Subject: [PATCH 38/67] templates: bump for v3.69.0 (#14998) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Automated bump of templates for v3.69.0 Triggered by user: @denolfe Co-authored-by: github-actions[bot] --- .../src/app/(payload)/admin/importMap.js | 6 +++- .../src/app/(payload)/admin/importMap.js | 2 ++ .../src/app/(payload)/admin/importMap.js | 2 ++ templates/with-cloudflare-d1/package.json | 12 ++++---- .../src/app/(payload)/admin/importMap.js | 6 +++- templates/with-postgres/.env.example | 2 +- templates/with-postgres/package.json | 10 +++---- .../src/app/(payload)/admin/importMap.js | 6 +++- ...tial.json => 20251219_215121_initial.json} | 2 +- ..._initial.ts => 20251219_215121_initial.ts} | 0 .../with-postgres/src/migrations/index.ts | 8 +++--- templates/with-vercel-mongodb/.env.example | 2 +- templates/with-vercel-mongodb/package.json | 14 +++++----- .../src/app/(payload)/admin/importMap.js | 2 ++ templates/with-vercel-postgres/package.json | 14 +++++----- .../src/app/(payload)/admin/importMap.js | 2 ++ ...tial.json => 20251219_215042_initial.json} | 2 +- ..._initial.ts => 20251219_215042_initial.ts} | 0 .../src/migrations/index.ts | 8 +++--- templates/with-vercel-website/package.json | 28 +++++++++---------- .../src/app/(payload)/admin/importMap.js | 2 ++ ...tial.json => 20251219_215102_initial.json} | 2 +- ..._initial.ts => 20251219_215102_initial.ts} | 0 .../src/migrations/index.ts | 8 +++--- 24 files changed, 81 insertions(+), 59 deletions(-) rename templates/with-postgres/src/migrations/{20251216_194340_initial.json => 20251219_215121_initial.json} (99%) rename templates/with-postgres/src/migrations/{20251216_194340_initial.ts => 20251219_215121_initial.ts} (100%) rename templates/with-vercel-postgres/src/migrations/{20251216_194325_initial.json => 20251219_215042_initial.json} (99%) rename templates/with-vercel-postgres/src/migrations/{20251216_194325_initial.ts => 20251219_215042_initial.ts} (100%) rename templates/with-vercel-website/src/migrations/{20251216_194333_initial.json => 20251219_215102_initial.json} (99%) rename templates/with-vercel-website/src/migrations/{20251216_194333_initial.ts => 20251219_215102_initial.ts} (100%) diff --git a/templates/blank/src/app/(payload)/admin/importMap.js b/templates/blank/src/app/(payload)/admin/importMap.js index 8ef7021383f..07ae7334573 100644 --- a/templates/blank/src/app/(payload)/admin/importMap.js +++ b/templates/blank/src/app/(payload)/admin/importMap.js @@ -1 +1,5 @@ -export const importMap = {} +import { CollectionCards as CollectionCards_ab83ff7e88da8d3530831f296ec4756a } from '@payloadcms/ui/rsc' + +export const importMap = { + '@payloadcms/ui/rsc#CollectionCards': CollectionCards_ab83ff7e88da8d3530831f296ec4756a, +} diff --git a/templates/ecommerce/src/app/(payload)/admin/importMap.js b/templates/ecommerce/src/app/(payload)/admin/importMap.js index 57d1b2a210b..2553d7d1785 100644 --- a/templates/ecommerce/src/app/(payload)/admin/importMap.js +++ b/templates/ecommerce/src/app/(payload)/admin/importMap.js @@ -24,6 +24,7 @@ import { PriceInput as PriceInput_b91672ccd6e8b071c11142ab941fedfb } from '@payl import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { BeforeDashboard as BeforeDashboard_1a7510af427896d367a49dbf838d2de6 } from '@/components/BeforeDashboard' import { BeforeLogin as BeforeLogin_8a7ab0eb7ab5c511aba12e68480bfe5e } from '@/components/BeforeLogin' +import { CollectionCards as CollectionCards_ab83ff7e88da8d3530831f296ec4756a } from '@payloadcms/ui/rsc' export const importMap = { '@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell': @@ -73,4 +74,5 @@ export const importMap = { HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, '@/components/BeforeDashboard#BeforeDashboard': BeforeDashboard_1a7510af427896d367a49dbf838d2de6, '@/components/BeforeLogin#BeforeLogin': BeforeLogin_8a7ab0eb7ab5c511aba12e68480bfe5e, + '@payloadcms/ui/rsc#CollectionCards': CollectionCards_ab83ff7e88da8d3530831f296ec4756a, } diff --git a/templates/website/src/app/(payload)/admin/importMap.js b/templates/website/src/app/(payload)/admin/importMap.js index e3aef27a9c3..e2211686971 100644 --- a/templates/website/src/app/(payload)/admin/importMap.js +++ b/templates/website/src/app/(payload)/admin/importMap.js @@ -26,6 +26,7 @@ import { RowLabel as RowLabel_ec255a65fa6fa8d1faeb09cf35284224 } from '@/Header/ import { RowLabel as RowLabel_1f6ff6ff633e3695d348f4f3c58f1466 } from '@/Footer/RowLabel' import { default as default_1a7510af427896d367a49dbf838d2de6 } from '@/components/BeforeDashboard' import { default as default_8a7ab0eb7ab5c511aba12e68480bfe5e } from '@/components/BeforeLogin' +import { CollectionCards as CollectionCards_ab83ff7e88da8d3530831f296ec4756a } from '@payloadcms/ui/rsc' export const importMap = { '@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell': @@ -74,4 +75,5 @@ export const importMap = { '@/Footer/RowLabel#RowLabel': RowLabel_1f6ff6ff633e3695d348f4f3c58f1466, '@/components/BeforeDashboard#default': default_1a7510af427896d367a49dbf838d2de6, '@/components/BeforeLogin#default': default_8a7ab0eb7ab5c511aba12e68480bfe5e, + '@payloadcms/ui/rsc#CollectionCards': CollectionCards_ab83ff7e88da8d3530831f296ec4756a, } diff --git a/templates/with-cloudflare-d1/package.json b/templates/with-cloudflare-d1/package.json index 3c71dbaf93f..bd22efafac6 100644 --- a/templates/with-cloudflare-d1/package.json +++ b/templates/with-cloudflare-d1/package.json @@ -26,16 +26,16 @@ }, "dependencies": { "@opennextjs/cloudflare": "^1.11.0", - "@payloadcms/db-d1-sqlite": "3.68.5", - "@payloadcms/next": "3.68.5", - "@payloadcms/richtext-lexical": "3.68.5", - "@payloadcms/storage-r2": "3.68.5", - "@payloadcms/ui": "3.68.5", + "@payloadcms/db-d1-sqlite": "3.69.0", + "@payloadcms/next": "3.69.0", + "@payloadcms/richtext-lexical": "3.69.0", + "@payloadcms/storage-r2": "3.69.0", + "@payloadcms/ui": "3.69.0", "cross-env": "^7.0.3", "dotenv": "16.4.7", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.68.5", + "payload": "3.69.0", "react": "19.2.1", "react-dom": "19.2.1" }, diff --git a/templates/with-cloudflare-d1/src/app/(payload)/admin/importMap.js b/templates/with-cloudflare-d1/src/app/(payload)/admin/importMap.js index 8ef7021383f..07ae7334573 100644 --- a/templates/with-cloudflare-d1/src/app/(payload)/admin/importMap.js +++ b/templates/with-cloudflare-d1/src/app/(payload)/admin/importMap.js @@ -1 +1,5 @@ -export const importMap = {} +import { CollectionCards as CollectionCards_ab83ff7e88da8d3530831f296ec4756a } from '@payloadcms/ui/rsc' + +export const importMap = { + '@payloadcms/ui/rsc#CollectionCards': CollectionCards_ab83ff7e88da8d3530831f296ec4756a, +} diff --git a/templates/with-postgres/.env.example b/templates/with-postgres/.env.example index c14561da4e6..4ef2fb40f8b 100644 --- a/templates/with-postgres/.env.example +++ b/templates/with-postgres/.env.example @@ -1,2 +1,2 @@ DATABASE_URL=postgresql://127.0.0.1:5432/your-database-name -PAYLOAD_SECRET=YOUR_SECRET_HERE +PAYLOAD_SECRET=YOUR_SECRET_HERE \ No newline at end of file diff --git a/templates/with-postgres/package.json b/templates/with-postgres/package.json index 86d822a7142..f16b5506207 100644 --- a/templates/with-postgres/package.json +++ b/templates/with-postgres/package.json @@ -19,14 +19,14 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/db-postgres": "3.68.5", - "@payloadcms/next": "3.68.5", - "@payloadcms/richtext-lexical": "3.68.5", - "@payloadcms/ui": "3.68.5", + "@payloadcms/db-postgres": "3.69.0", + "@payloadcms/next": "3.69.0", + "@payloadcms/richtext-lexical": "3.69.0", + "@payloadcms/ui": "3.69.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.68.5", + "payload": "3.69.0", "react": "19.2.1", "react-dom": "19.2.1", "sharp": "0.34.2" diff --git a/templates/with-postgres/src/app/(payload)/admin/importMap.js b/templates/with-postgres/src/app/(payload)/admin/importMap.js index 8ef7021383f..07ae7334573 100644 --- a/templates/with-postgres/src/app/(payload)/admin/importMap.js +++ b/templates/with-postgres/src/app/(payload)/admin/importMap.js @@ -1 +1,5 @@ -export const importMap = {} +import { CollectionCards as CollectionCards_ab83ff7e88da8d3530831f296ec4756a } from '@payloadcms/ui/rsc' + +export const importMap = { + '@payloadcms/ui/rsc#CollectionCards': CollectionCards_ab83ff7e88da8d3530831f296ec4756a, +} diff --git a/templates/with-postgres/src/migrations/20251216_194340_initial.json b/templates/with-postgres/src/migrations/20251219_215121_initial.json similarity index 99% rename from templates/with-postgres/src/migrations/20251216_194340_initial.json rename to templates/with-postgres/src/migrations/20251219_215121_initial.json index 3fa5791b871..e24bf9d8964 100644 --- a/templates/with-postgres/src/migrations/20251216_194340_initial.json +++ b/templates/with-postgres/src/migrations/20251219_215121_initial.json @@ -934,6 +934,6 @@ "tables": {}, "columns": {} }, - "id": "0feee724-64cb-470b-ba33-0c37b438502a", + "id": "467e8bdd-a159-49fd-850e-ba395659b979", "prevId": "00000000-0000-0000-0000-000000000000" } diff --git a/templates/with-postgres/src/migrations/20251216_194340_initial.ts b/templates/with-postgres/src/migrations/20251219_215121_initial.ts similarity index 100% rename from templates/with-postgres/src/migrations/20251216_194340_initial.ts rename to templates/with-postgres/src/migrations/20251219_215121_initial.ts diff --git a/templates/with-postgres/src/migrations/index.ts b/templates/with-postgres/src/migrations/index.ts index 2bbf53e80d0..53cc3e79199 100644 --- a/templates/with-postgres/src/migrations/index.ts +++ b/templates/with-postgres/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20251216_194340_initial from './20251216_194340_initial' +import * as migration_20251219_215121_initial from './20251219_215121_initial' export const migrations = [ { - up: migration_20251216_194340_initial.up, - down: migration_20251216_194340_initial.down, - name: '20251216_194340_initial', + up: migration_20251219_215121_initial.up, + down: migration_20251219_215121_initial.down, + name: '20251219_215121_initial', }, ] diff --git a/templates/with-vercel-mongodb/.env.example b/templates/with-vercel-mongodb/.env.example index 42067211337..ac0168ebefd 100644 --- a/templates/with-vercel-mongodb/.env.example +++ b/templates/with-vercel-mongodb/.env.example @@ -1,2 +1,2 @@ MONGODB_URL=mongodb://127.0.0.1/your-database-name -PAYLOAD_SECRET=YOUR_SECRET_HERE +PAYLOAD_SECRET=YOUR_SECRET_HERE \ No newline at end of file diff --git a/templates/with-vercel-mongodb/package.json b/templates/with-vercel-mongodb/package.json index b23cf2101f4..c65ec14c36a 100644 --- a/templates/with-vercel-mongodb/package.json +++ b/templates/with-vercel-mongodb/package.json @@ -18,15 +18,15 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/db-mongodb": "3.68.5", - "@payloadcms/next": "3.68.5", - "@payloadcms/richtext-lexical": "3.68.5", - "@payloadcms/storage-vercel-blob": "3.68.5", - "@payloadcms/ui": "3.68.5", + "@payloadcms/db-mongodb": "3.69.0", + "@payloadcms/next": "3.69.0", + "@payloadcms/richtext-lexical": "3.69.0", + "@payloadcms/storage-vercel-blob": "3.69.0", + "@payloadcms/ui": "3.69.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.68.5", + "payload": "3.69.0", "react": "19.2.1", "react-dom": "19.2.1" }, @@ -48,7 +48,7 @@ "vite-tsconfig-paths": "5.1.4", "vitest": "3.2.3" }, - "packageManager": "pnpm@10.26.0", + "packageManager": "pnpm@10.26.1", "engines": { "node": "^18.20.2 || >=20.9.0" }, diff --git a/templates/with-vercel-mongodb/src/app/(payload)/admin/importMap.js b/templates/with-vercel-mongodb/src/app/(payload)/admin/importMap.js index ad41a392a55..d5166907a1e 100644 --- a/templates/with-vercel-mongodb/src/app/(payload)/admin/importMap.js +++ b/templates/with-vercel-mongodb/src/app/(payload)/admin/importMap.js @@ -1,6 +1,8 @@ import { VercelBlobClientUploadHandler as VercelBlobClientUploadHandler_16c82c5e25f430251a3e3ba57219ff4e } from '@payloadcms/storage-vercel-blob/client' +import { CollectionCards as CollectionCards_ab83ff7e88da8d3530831f296ec4756a } from '@payloadcms/ui/rsc' export const importMap = { '@payloadcms/storage-vercel-blob/client#VercelBlobClientUploadHandler': VercelBlobClientUploadHandler_16c82c5e25f430251a3e3ba57219ff4e, + '@payloadcms/ui/rsc#CollectionCards': CollectionCards_ab83ff7e88da8d3530831f296ec4756a, } diff --git a/templates/with-vercel-postgres/package.json b/templates/with-vercel-postgres/package.json index b9b3a92ed07..f2cfc16dc92 100644 --- a/templates/with-vercel-postgres/package.json +++ b/templates/with-vercel-postgres/package.json @@ -19,15 +19,15 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/db-vercel-postgres": "3.68.5", - "@payloadcms/next": "3.68.5", - "@payloadcms/richtext-lexical": "3.68.5", - "@payloadcms/storage-vercel-blob": "3.68.5", - "@payloadcms/ui": "3.68.5", + "@payloadcms/db-vercel-postgres": "3.69.0", + "@payloadcms/next": "3.69.0", + "@payloadcms/richtext-lexical": "3.69.0", + "@payloadcms/storage-vercel-blob": "3.69.0", + "@payloadcms/ui": "3.69.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.68.5", + "payload": "3.69.0", "react": "19.2.1", "react-dom": "19.2.1" }, @@ -49,7 +49,7 @@ "vite-tsconfig-paths": "5.1.4", "vitest": "3.2.3" }, - "packageManager": "pnpm@10.26.0", + "packageManager": "pnpm@10.26.1", "engines": { "node": "^18.20.2 || >=20.9.0" }, diff --git a/templates/with-vercel-postgres/src/app/(payload)/admin/importMap.js b/templates/with-vercel-postgres/src/app/(payload)/admin/importMap.js index ad41a392a55..d5166907a1e 100644 --- a/templates/with-vercel-postgres/src/app/(payload)/admin/importMap.js +++ b/templates/with-vercel-postgres/src/app/(payload)/admin/importMap.js @@ -1,6 +1,8 @@ import { VercelBlobClientUploadHandler as VercelBlobClientUploadHandler_16c82c5e25f430251a3e3ba57219ff4e } from '@payloadcms/storage-vercel-blob/client' +import { CollectionCards as CollectionCards_ab83ff7e88da8d3530831f296ec4756a } from '@payloadcms/ui/rsc' export const importMap = { '@payloadcms/storage-vercel-blob/client#VercelBlobClientUploadHandler': VercelBlobClientUploadHandler_16c82c5e25f430251a3e3ba57219ff4e, + '@payloadcms/ui/rsc#CollectionCards': CollectionCards_ab83ff7e88da8d3530831f296ec4756a, } diff --git a/templates/with-vercel-postgres/src/migrations/20251216_194325_initial.json b/templates/with-vercel-postgres/src/migrations/20251219_215042_initial.json similarity index 99% rename from templates/with-vercel-postgres/src/migrations/20251216_194325_initial.json rename to templates/with-vercel-postgres/src/migrations/20251219_215042_initial.json index 788eb1825b3..52631e9b98a 100644 --- a/templates/with-vercel-postgres/src/migrations/20251216_194325_initial.json +++ b/templates/with-vercel-postgres/src/migrations/20251219_215042_initial.json @@ -934,6 +934,6 @@ "tables": {}, "columns": {} }, - "id": "633ac0dd-e243-41bc-8339-c40677f18590", + "id": "a58a4163-b21a-4c60-8a8e-cc9aa119df75", "prevId": "00000000-0000-0000-0000-000000000000" } diff --git a/templates/with-vercel-postgres/src/migrations/20251216_194325_initial.ts b/templates/with-vercel-postgres/src/migrations/20251219_215042_initial.ts similarity index 100% rename from templates/with-vercel-postgres/src/migrations/20251216_194325_initial.ts rename to templates/with-vercel-postgres/src/migrations/20251219_215042_initial.ts diff --git a/templates/with-vercel-postgres/src/migrations/index.ts b/templates/with-vercel-postgres/src/migrations/index.ts index b4f4bbc2268..e747e61a406 100644 --- a/templates/with-vercel-postgres/src/migrations/index.ts +++ b/templates/with-vercel-postgres/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20251216_194325_initial from './20251216_194325_initial' +import * as migration_20251219_215042_initial from './20251219_215042_initial' export const migrations = [ { - up: migration_20251216_194325_initial.up, - down: migration_20251216_194325_initial.down, - name: '20251216_194325_initial', + up: migration_20251219_215042_initial.up, + down: migration_20251219_215042_initial.down, + name: '20251219_215042_initial', }, ] diff --git a/templates/with-vercel-website/package.json b/templates/with-vercel-website/package.json index 46b657895c0..3aded08005b 100644 --- a/templates/with-vercel-website/package.json +++ b/templates/with-vercel-website/package.json @@ -23,18 +23,18 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/admin-bar": "3.68.5", - "@payloadcms/db-vercel-postgres": "3.68.5", - "@payloadcms/live-preview-react": "3.68.5", - "@payloadcms/next": "3.68.5", - "@payloadcms/plugin-form-builder": "3.68.5", - "@payloadcms/plugin-nested-docs": "3.68.5", - "@payloadcms/plugin-redirects": "3.68.5", - "@payloadcms/plugin-search": "3.68.5", - "@payloadcms/plugin-seo": "3.68.5", - "@payloadcms/richtext-lexical": "3.68.5", - "@payloadcms/storage-vercel-blob": "3.68.5", - "@payloadcms/ui": "3.68.5", + "@payloadcms/admin-bar": "3.69.0", + "@payloadcms/db-vercel-postgres": "3.69.0", + "@payloadcms/live-preview-react": "3.69.0", + "@payloadcms/next": "3.69.0", + "@payloadcms/plugin-form-builder": "3.69.0", + "@payloadcms/plugin-nested-docs": "3.69.0", + "@payloadcms/plugin-redirects": "3.69.0", + "@payloadcms/plugin-search": "3.69.0", + "@payloadcms/plugin-seo": "3.69.0", + "@payloadcms/richtext-lexical": "3.69.0", + "@payloadcms/storage-vercel-blob": "3.69.0", + "@payloadcms/ui": "3.69.0", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-select": "^2.0.0", @@ -48,7 +48,7 @@ "lucide-react": "^0.378.0", "next": "15.4.10", "next-sitemap": "^4.2.3", - "payload": "3.68.5", + "payload": "3.69.0", "prism-react-renderer": "^2.3.1", "react": "19.2.1", "react-dom": "19.2.1", @@ -81,7 +81,7 @@ "vite-tsconfig-paths": "5.1.4", "vitest": "3.2.3" }, - "packageManager": "pnpm@10.26.0", + "packageManager": "pnpm@10.26.1", "engines": { "node": "^18.20.2 || >=20.9.0" }, diff --git a/templates/with-vercel-website/src/app/(payload)/admin/importMap.js b/templates/with-vercel-website/src/app/(payload)/admin/importMap.js index 6fd0077e328..d929c9aae10 100644 --- a/templates/with-vercel-website/src/app/(payload)/admin/importMap.js +++ b/templates/with-vercel-website/src/app/(payload)/admin/importMap.js @@ -27,6 +27,7 @@ import { RowLabel as RowLabel_1f6ff6ff633e3695d348f4f3c58f1466 } from '@/Footer/ import { default as default_1a7510af427896d367a49dbf838d2de6 } from '@/components/BeforeDashboard' import { default as default_8a7ab0eb7ab5c511aba12e68480bfe5e } from '@/components/BeforeLogin' import { VercelBlobClientUploadHandler as VercelBlobClientUploadHandler_16c82c5e25f430251a3e3ba57219ff4e } from '@payloadcms/storage-vercel-blob/client' +import { CollectionCards as CollectionCards_ab83ff7e88da8d3530831f296ec4756a } from '@payloadcms/ui/rsc' export const importMap = { '@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell': @@ -77,4 +78,5 @@ export const importMap = { '@/components/BeforeLogin#default': default_8a7ab0eb7ab5c511aba12e68480bfe5e, '@payloadcms/storage-vercel-blob/client#VercelBlobClientUploadHandler': VercelBlobClientUploadHandler_16c82c5e25f430251a3e3ba57219ff4e, + '@payloadcms/ui/rsc#CollectionCards': CollectionCards_ab83ff7e88da8d3530831f296ec4756a, } diff --git a/templates/with-vercel-website/src/migrations/20251216_194333_initial.json b/templates/with-vercel-website/src/migrations/20251219_215102_initial.json similarity index 99% rename from templates/with-vercel-website/src/migrations/20251216_194333_initial.json rename to templates/with-vercel-website/src/migrations/20251219_215102_initial.json index d5202681594..d68bf187faa 100644 --- a/templates/with-vercel-website/src/migrations/20251216_194333_initial.json +++ b/templates/with-vercel-website/src/migrations/20251219_215102_initial.json @@ -9181,6 +9181,6 @@ "tables": {}, "columns": {} }, - "id": "39a710ea-5b17-43d5-bf1c-6010b856e4d7", + "id": "6b0e67eb-144f-4853-8c3e-309797d35a20", "prevId": "00000000-0000-0000-0000-000000000000" } diff --git a/templates/with-vercel-website/src/migrations/20251216_194333_initial.ts b/templates/with-vercel-website/src/migrations/20251219_215102_initial.ts similarity index 100% rename from templates/with-vercel-website/src/migrations/20251216_194333_initial.ts rename to templates/with-vercel-website/src/migrations/20251219_215102_initial.ts diff --git a/templates/with-vercel-website/src/migrations/index.ts b/templates/with-vercel-website/src/migrations/index.ts index 9db85afa116..8488648ffba 100644 --- a/templates/with-vercel-website/src/migrations/index.ts +++ b/templates/with-vercel-website/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20251216_194333_initial from './20251216_194333_initial' +import * as migration_20251219_215102_initial from './20251219_215102_initial' export const migrations = [ { - up: migration_20251216_194333_initial.up, - down: migration_20251216_194333_initial.down, - name: '20251216_194333_initial', + up: migration_20251219_215102_initial.up, + down: migration_20251219_215102_initial.down, + name: '20251219_215102_initial', }, ] From cc8a9b02789a5e5a98746d3644703bd0bb18cdec Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Tue, 23 Dec 2025 08:52:23 -0800 Subject: [PATCH 39/67] fix(next): turbopack build version check not working for 16.1.1 canaries (#15005) Currently, turbopack build is disabled for Next.js 16.1.1-canary.1 due to an incorrect version check. This PR fixes this version check to allow turbopack build on all newer Next.js canaries. --- packages/next/src/withPayload/withPayload.utils.ts | 8 ++++++-- packages/next/src/withPayload/withPayloadLegacy.ts | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/next/src/withPayload/withPayload.utils.ts b/packages/next/src/withPayload/withPayload.utils.ts index 657706a68e9..bad87065bc5 100644 --- a/packages/next/src/withPayload/withPayload.utils.ts +++ b/packages/next/src/withPayload/withPayload.utils.ts @@ -114,7 +114,7 @@ export function supportsTurbopackExternalizeTransitiveDependencies( return false } - const { canaryVersion, major, minor } = version + const { canaryVersion, major, minor, patch } = version if (major === undefined || minor === undefined) { return false @@ -129,11 +129,15 @@ export function supportsTurbopackExternalizeTransitiveDependencies( return true } if (minor === 1) { + // 16.1.1+ and canaries support this feature + if (patch > 0) { + return true + } if (canaryVersion !== undefined) { // 16.1.0-canary.3+ return canaryVersion >= 3 } else { - // Assume that Next.js 16.1 inherits support for this feature from the canary release + // Next.js 16.1.0 return true } } diff --git a/packages/next/src/withPayload/withPayloadLegacy.ts b/packages/next/src/withPayload/withPayloadLegacy.ts index d942f1a23a3..d906568f494 100644 --- a/packages/next/src/withPayload/withPayloadLegacy.ts +++ b/packages/next/src/withPayload/withPayloadLegacy.ts @@ -48,7 +48,7 @@ export const withPayloadLegacy = (nextConfig: NextConfig = {}): NextConfig => { if (isBuild && (isTurbopackNextjs15 || isTurbopackNextjs16)) { throw new Error( - 'Your Next.js and Payload versions do not support using Turbopack for production builds. Please upgrade to Next.js 16.1.0 or, if not yet released, the latest canary release.', + 'Your Next.js version does not support using Turbopack for production builds. The *minimum* Next.js version required for Turbopack Builds is 16.1.0. Please upgrade to the latest supported Next.js version to resolve this error.', ) } From c89800e8a0b1762ad52a7317c1f29d6bd2babb0a Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Tue, 23 Dec 2025 08:52:54 -0800 Subject: [PATCH 40/67] fix: warning during Next.js build "the request of a dependency is an expression" (#15007) Fixes https://github.com/payloadcms/payload/issues/15006 https://github.com/payloadcms/payload/pull/14337 introduced a next build warning, because the `eval` around `await import` statements has been removed. Unlike jest, vitest is fine with it. But during Next.js build, the bundler will throw a `"Critical dependency: the request of a dependency is an expression"` warning. This PR fixes this warning by adding back the eval statement around the import. It does not add back the conditional require statement - that part was only necessary to appease jest. For vitest, we have to directly call `await import()`. Using eval in vitest will throw an `ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING` error. ## Preventing this regression in the future This PR adds a comment above the eval explaining why it's needed. Previously this was missing, and we only had a comment explaining why the `require` was needed. Additionally, the reason this was not caught in CI was because warnings during next build did not fail the build script. This PR adds an additional check in `build-template-with-local-pkgs.ts` that throws an error if a warning was detected during next build. You can find the CI failure here: https://github.com/payloadcms/payload/actions/runs/20402288354/job/58626594247?pr=15007 (CI run from commit that added this check, before the commit that fixed it) Now, if this ever happens again, our CI will fail and prevent a regression. ## More Tests This PR adds additional database and job queue tests that verify that the job queue handler and migration file imports work correctly. --- .github/workflows/main.yml | 2 + .../src/predefinedMigrations/__testing__.ts | 12 ++ packages/payload/package.json | 8 + .../src/__testing__/predefinedMigration.js | 18 +++ packages/payload/src/bin/migrate.ts | 12 +- .../migrations/getPredefinedMigration.ts | 26 +++- .../database/migrations/readMigrationFiles.ts | 13 +- .../runJobs/runJob/importHandlerPath.ts | 12 +- .../payload/src/utilities/dynamicImport.ts | 28 ++++ test/database/int.spec.ts | 125 +++++++-------- test/database/migrations-cli.int.spec.ts | 139 +++++++++++++++++ test/database/payload-types.ts | 1 + .../testPluginMigration.ts | 12 ++ test/eslint.config.js | 7 + test/helpers/vitest.ts | 93 ++++++++++++ test/queues/e2e.spec.ts | 142 ++++++++++++++++++ test/queues/payload-types.ts | 34 ++++- .../src/build-template-with-local-pkgs.ts | 66 +++++++- 18 files changed, 654 insertions(+), 96 deletions(-) create mode 100644 packages/db-mongodb/src/predefinedMigrations/__testing__.ts create mode 100644 packages/payload/src/__testing__/predefinedMigration.js create mode 100644 packages/payload/src/utilities/dynamicImport.ts create mode 100644 test/database/migrations-cli.int.spec.ts create mode 100644 test/database/predefinedMigrations/testPluginMigration.ts create mode 100644 test/helpers/vitest.ts create mode 100644 test/queues/e2e.spec.ts diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 66ce2bd001b..b334daa8326 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -287,6 +287,7 @@ jobs: - plugin-nested-docs - plugin-redirects - plugin-seo + - queues - sort - server-url - trash @@ -439,6 +440,7 @@ jobs: - plugin-multi-tenant - plugin-nested-docs - plugin-seo + - queues - sort - trash - versions diff --git a/packages/db-mongodb/src/predefinedMigrations/__testing__.ts b/packages/db-mongodb/src/predefinedMigrations/__testing__.ts new file mode 100644 index 00000000000..96b8506bde0 --- /dev/null +++ b/packages/db-mongodb/src/predefinedMigrations/__testing__.ts @@ -0,0 +1,12 @@ +/** + * Test predefined migration for testing plugin-style module specifier imports. + * This is used in integration tests to verify that external packages can export + * predefined migrations via their package.json exports. + */ +const imports = `` +const upSQL = ` // Test predefined migration from @payloadcms/db-mongodb/__testing__ + payload.logger.info('Test migration UP executed')` +const downSQL = ` // Test predefined migration DOWN + payload.logger.info('Test migration DOWN executed')` + +export { downSQL, imports, upSQL } diff --git a/packages/payload/package.json b/packages/payload/package.json index 80c7e4b9e3b..36759436695 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -64,6 +64,10 @@ "import": "./src/exports/i18n/*.ts", "types": "./src/exports/i18n/*.ts", "default": "./src/exports/i18n/*.ts" + }, + "./__testing__/predefinedMigration": { + "import": "./src/__testing__/predefinedMigration.js", + "default": "./src/__testing__/predefinedMigration.js" } }, "main": "./src/index.ts", @@ -176,6 +180,10 @@ "import": "./dist/exports/i18n/*.js", "types": "./dist/exports/i18n/*.d.ts", "default": "./dist/exports/i18n/*.js" + }, + "./__testing__/predefinedMigration": { + "import": "./dist/__testing__/predefinedMigration.js", + "default": "./dist/__testing__/predefinedMigration.js" } }, "main": "./dist/index.js", diff --git a/packages/payload/src/__testing__/predefinedMigration.js b/packages/payload/src/__testing__/predefinedMigration.js new file mode 100644 index 00000000000..15f19c841b1 --- /dev/null +++ b/packages/payload/src/__testing__/predefinedMigration.js @@ -0,0 +1,18 @@ +/** + * Test predefined migration for testing plugin-style module specifier imports. + * This is used in integration tests to verify that external packages (without @payloadcms/db-* prefix) + * can export predefined migrations via their package.json exports. + * + * This tests the second code path in getPredefinedMigration.ts (lines 56-72) + * + * NOTE: This is a .js file (not .ts) because Node.js with --no-experimental-strip-types + * cannot import .ts files via module specifiers. Absolute file paths work because Vitest's + * loader intercepts file:// URLs, but module specifiers are resolved by Node.js first. + */ +const imports = `` +const upSQL = ` // Test predefined migration from payload/__testing__/predefinedMigration + payload.logger.info('Test migration UP from payload package executed')` +const downSQL = ` // Test predefined migration DOWN from payload package + payload.logger.info('Test migration DOWN from payload package executed')` + +export { downSQL, imports, upSQL } diff --git a/packages/payload/src/bin/migrate.ts b/packages/payload/src/bin/migrate.ts index 624e693d3f3..52d21ad9071 100644 --- a/packages/payload/src/bin/migrate.ts +++ b/packages/payload/src/bin/migrate.ts @@ -28,10 +28,15 @@ const availableCommandsMsg = `Available commands: ${availableCommands.join(', ') type Args = { config: SanitizedConfig + /** + * Override the migration directory. Useful for testing when the CWD differs + * from where the test config expects migrations to be stored. + */ + migrationDir?: string parsedArgs: ParsedArgs } -export const migrate = async ({ config, parsedArgs }: Args): Promise => { +export const migrate = async ({ config, migrationDir, parsedArgs }: Args): Promise => { const { _: args, file, forceAcceptWarning: forceAcceptFromProps, help } = parsedArgs const formattedArgs = Object.keys(parsedArgs) @@ -75,6 +80,11 @@ export const migrate = async ({ config, parsedArgs }: Args): Promise => { throw new Error('No database adapter found') } + // Override migrationDir if provided (useful for testing) + if (migrationDir) { + adapter.migrationDir = migrationDir + } + if (!args.length) { payload.logger.error({ msg: `No migration command provided. ${availableCommandsMsg}`, diff --git a/packages/payload/src/database/migrations/getPredefinedMigration.ts b/packages/payload/src/database/migrations/getPredefinedMigration.ts index eaa425f9d61..a3d63b05216 100644 --- a/packages/payload/src/database/migrations/getPredefinedMigration.ts +++ b/packages/payload/src/database/migrations/getPredefinedMigration.ts @@ -1,12 +1,19 @@ import fs from 'fs' import path from 'path' -import { pathToFileURL } from 'url' import type { Payload } from '../../index.js' import type { MigrationTemplateArgs } from '../types.js' +import { dynamicImport } from '../../utilities/dynamicImport.js' + /** - * Get predefined migration 'up', 'down' and 'imports' + * Get predefined migration 'up', 'down' and 'imports'. + * + * Supports two import methods: + * 1. @payloadcms/db-* packages: Loads from adapter's predefinedMigrations folder directly (no package.json export needed) + * Example: `--file @payloadcms/db-mongodb/relationships-v2-v3` + * 2. Any other package/path: Uses dynamic import via package.json exports or absolute file paths + * Example: `--file @payloadcms/plugin-seo/someMigration` or `--file /absolute/path/to/migration.ts` */ export const getPredefinedMigration = async ({ dirname, @@ -19,18 +26,20 @@ export const getPredefinedMigration = async ({ migrationName?: string payload: Payload }): Promise => { - // Check for predefined migration. - // Either passed in via --file or prefixed with '@payloadcms/db-mongodb/' for example const importPath = file ?? migrationNameArg + // Path 1: @payloadcms/db-* adapters - load directly from predefinedMigrations folder + // These don't need package.json exports; files are resolved relative to adapter's dirname if (importPath?.startsWith('@payloadcms/db-')) { - // removes the package name from the migrationName. const migrationName = importPath.split('/').slice(2).join('/') let cleanPath = path.join(dirname, `./predefinedMigrations/${migrationName}`) if (fs.existsSync(`${cleanPath}.mjs`)) { cleanPath = `${cleanPath}.mjs` } else if (fs.existsSync(`${cleanPath}.js`)) { cleanPath = `${cleanPath}.js` + } else if (fs.existsSync(`${cleanPath}.ts`)) { + // Support .ts in development when running from source + cleanPath = `${cleanPath}.ts` } else { payload.logger.error({ msg: `Canned migration ${migrationName} not found.`, @@ -38,9 +47,8 @@ export const getPredefinedMigration = async ({ process.exit(1) } cleanPath = cleanPath.replaceAll('\\', '/') - const moduleURL = pathToFileURL(cleanPath) try { - const { downSQL, imports, upSQL } = await eval(`import('${moduleURL.href}')`) + const { downSQL, imports, upSQL } = await dynamicImport(cleanPath) return { downSQL, imports, @@ -54,8 +62,10 @@ export const getPredefinedMigration = async ({ process.exit(1) } } else if (importPath) { + // Path 2: Any other package or file path - use dynamic import + // Supports: package.json exports (e.g. @payloadcms/plugin-seo/migration) or absolute file paths try { - const { downSQL, imports, upSQL } = await eval(`import('${importPath}')`) + const { downSQL, imports, upSQL } = await dynamicImport(importPath) return { downSQL, imports, diff --git a/packages/payload/src/database/migrations/readMigrationFiles.ts b/packages/payload/src/database/migrations/readMigrationFiles.ts index 2d25b05f84c..abefa39a0ea 100644 --- a/packages/payload/src/database/migrations/readMigrationFiles.ts +++ b/packages/payload/src/database/migrations/readMigrationFiles.ts @@ -4,6 +4,8 @@ import path from 'path' import type { Payload } from '../../index.js' import type { Migration } from '../types.js' +import { dynamicImport } from '../../utilities/dynamicImport.js' + /** * Read the migration files from disk */ @@ -35,10 +37,13 @@ export const readMigrationFiles = async ({ return Promise.all( files.map(async (filePath) => { - let migration = await import(filePath.replaceAll('\\', '/')) - if ('default' in migration) { - migration = migration.default - } + const migrationModule = await dynamicImport< + | { + default: Migration + } + | Migration + >(filePath) + const migration = 'default' in migrationModule ? migrationModule.default : migrationModule const result: Migration = { name: path.basename(filePath).split('.')[0]!, diff --git a/packages/payload/src/queues/operations/runJobs/runJob/importHandlerPath.ts b/packages/payload/src/queues/operations/runJobs/runJob/importHandlerPath.ts index b9ed161321c..87941c98ce0 100644 --- a/packages/payload/src/queues/operations/runJobs/runJob/importHandlerPath.ts +++ b/packages/payload/src/queues/operations/runJobs/runJob/importHandlerPath.ts @@ -1,5 +1,7 @@ import type { TaskConfig, TaskHandler, TaskType } from '../../../config/types/taskTypes.js' +import { dynamicImport } from '../../../../utilities/dynamicImport.js' + /** * Imports a handler function from a given path. */ @@ -7,9 +9,9 @@ export async function importHandlerPath(path: string): Promise { let runner!: T const [runnerPath, runnerImportName] = path.split('#') - let runnerModule + let runnerModule: Record try { - runnerModule = await import(runnerPath!.replaceAll('\\', '/')) + runnerModule = await dynamicImport>(runnerPath!) } catch (e) { throw new Error( `Error importing job queue handler module for path ${path}. This is an advanced feature that may require a sophisticated build pipeline, especially when using it in production or within Next.js, e.g. by calling opening the /api/payload-jobs/run endpoint. You will have to transpile the handler files separately and ensure they are available in the same location when the job is run. If you're using an endpoint to execute your jobs, it's recommended to define your handlers as functions directly in your Payload Config, or use import paths handlers outside of Next.js. Import Error: \n${e instanceof Error ? e.message : 'Unknown error'}`, @@ -18,17 +20,17 @@ export async function importHandlerPath(path: string): Promise { // If the path has indicated an #exportName, try to get it if (runnerImportName && runnerModule[runnerImportName]) { - runner = runnerModule[runnerImportName] + runner = runnerModule[runnerImportName] as T } // If there is a default export, use it if (!runner && runnerModule.default) { - runner = runnerModule.default + runner = runnerModule.default as T } // Finally, use whatever was imported if (!runner) { - runner = runnerModule + runner = runnerModule as T } return runner diff --git a/packages/payload/src/utilities/dynamicImport.ts b/packages/payload/src/utilities/dynamicImport.ts new file mode 100644 index 00000000000..ed5ba575944 --- /dev/null +++ b/packages/payload/src/utilities/dynamicImport.ts @@ -0,0 +1,28 @@ +import path from 'path' +import { pathToFileURL } from 'url' + +/** + * Dynamically imports a module from a file path or module specifier. + * + * Uses a direct `import()` in Vitest (where eval'd imports fail with ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING), + * and `eval(`import(...)`)` elsewhere to hide the import from Next.js bundler static analysis. + * + * @param modulePathOrSpecifier - Either an absolute file path or a module specifier (package name) + */ +export async function dynamicImport(modulePathOrSpecifier: string): Promise { + // Convert absolute file paths to file:// URLs, but leave package specifiers as-is + const importPath = path.isAbsolute(modulePathOrSpecifier) + ? pathToFileURL(modulePathOrSpecifier).href + : modulePathOrSpecifier + + // Vitest runs tests in a VM context where eval'd dynamic imports fail with + // ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING. Use direct import in test environment. + if (process.env.VITEST) { + return await import(importPath) + } + + // Without the eval, the Next.js bundler will throw this error when encountering the import statement: + // ⚠ Compiled with warnings in X.Xs + // Critical dependency: the request of a dependency is an expression + return await eval(`import('${importPath}')`) +} diff --git a/test/database/int.spec.ts b/test/database/int.spec.ts index 678c0540601..d296f822bde 100644 --- a/test/database/int.spec.ts +++ b/test/database/int.spec.ts @@ -29,15 +29,15 @@ import { } from 'payload' import { assert } from 'ts-essentials' import { fileURLToPath } from 'url' -import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest' +import { afterAll, beforeAll, beforeEach, expect } from 'vitest' import type { Global2, Post } from './payload-types.js' import { sanitizeQueryValue } from '../../packages/db-mongodb/src/queries/sanitizeQueryValue.js' import { devUser } from '../credentials.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' -import { isMongoose, mongooseList } from '../helpers/isMongoose.js' import removeFiles from '../helpers/removeFiles.js' +import { describe, it } from '../helpers/vitest.js' import { seed } from './seed.js' import { errorOnUnnamedFieldsSlug, fieldsPersistanceSlug, postsSlug } from './shared.js' @@ -52,8 +52,6 @@ const collection = postsSlug const title = 'title' process.env.PAYLOAD_CONFIG_PATH = path.join(dirname, 'config.ts') -const itMongo = process.env.PAYLOAD_DATABASE?.startsWith('mongodb') ? it : it.skip - describe('database', () => { beforeAll(async () => { process.env.SEED_IN_CONFIG_ONINIT = 'false' // Makes it so the payload config onInit seed is not run. Otherwise, the seed would be run unnecessarily twice for the initial test run - once for beforeEach and once for onInit @@ -609,8 +607,9 @@ describe('database', () => { await noTimestampsTestDB(true) }) - itMongo( + it( 'ensure timestamps are not created in update or create when timestamps are disabled even with allowAdditionalKeys true', + { db: 'mongo' }, async () => { const originalAllowAdditionalKeys = payload.db.allowAdditionalKeys payload.db.allowAdditionalKeys = true @@ -619,8 +618,9 @@ describe('database', () => { }, ) - itMongo( + it( 'ensure timestamps are not created in db adapter update or create when timestamps are disabled even with allowAdditionalKeys true', + { db: 'mongo' }, async () => { const originalAllowAdditionalKeys = payload.db.allowAdditionalKeys payload.db.allowAdditionalKeys = true @@ -1548,12 +1548,8 @@ describe('database', () => { ranFreshTest = true }) - it('should run migrate:down', async () => { - // known drizzle issue: https://github.com/payloadcms/payload/issues/4597 - if (!isMongoose(payload)) { - return - } - + // known drizzle issue: https://github.com/payloadcms/payload/issues/4597 + it('should run migrate:down', { db: 'mongo' }, async () => { // migrate existing if there any await payload.db.migrate() @@ -1586,11 +1582,8 @@ describe('database', () => { await payload.delete({ collection: 'payload-migrations', where: {} }) }) - it('should run migrate:refresh', async () => { - // known drizzle issue: https://github.com/payloadcms/payload/issues/4597 - if (!isMongoose(payload)) { - return - } + // known drizzle issue: https://github.com/payloadcms/payload/issues/4597 + it('should run migrate:refresh', { db: 'mongo' }, async () => { let error try { await payload.db.migrateRefresh() @@ -1607,11 +1600,8 @@ describe('database', () => { }) }) - it('should run migrate:reset', async () => { - // known drizzle issue: https://github.com/payloadcms/payload/issues/4597 - if (!isMongoose(payload)) { - return - } + // known drizzle issue: https://github.com/payloadcms/payload/issues/4597 + it('should run migrate:reset', { db: 'mongo' }, async () => { let error try { await payload.db.migrateReset() @@ -1730,6 +1720,7 @@ describe('database', () => { await payload.db.collections['relationships-migration'].deleteMany({}) await payload.db.versions['relationships-migration'].deleteMany({}) }) + }) describe('schema', () => { @@ -2764,11 +2755,7 @@ describe('database', () => { }) }) - const describeSQL = mongooseList.includes(process.env.PAYLOAD_DATABASE!) - ? describe.skip - : describe - - describeSQL('Schema generation', () => { + describe('Schema generation', { db: 'drizzle' }, () => { if ( process.env.PAYLOAD_DATABASE.includes('postgres') || process.env.PAYLOAD_DATABASE === 'supabase' @@ -5202,11 +5189,7 @@ describe('database', () => { await payload.db.connect() }) - it('ensure mongodb query sanitization does not duplicate IDs', () => { - if (!isMongoose(payload)) { - return - } - + it('ensure mongodb query sanitization does not duplicate IDs', { db: 'mongo' }, () => { const res: any = sanitizeQueryValue({ field: { name: '_id', @@ -5225,51 +5208,55 @@ describe('database', () => { expect(JSON.parse(JSON.stringify(res)).val[0]).toEqual('68378b649ca45274fb10126f') }) - itMongo('ensure mongodb respects collation when using collection in the config', async () => { - // Clear any existing documents - await payload.delete({ collection: 'simple', where: {} }) + it( + 'ensure mongodb respects collation when using collection in the config', + { db: 'mongo' }, + async () => { + // Clear any existing documents + await payload.delete({ collection: 'simple', where: {} }) - const expectedUnsortedItems = ['Євген', 'Віктор', 'Роман'] - const expectedSortedItems = ['Віктор', 'Євген', 'Роман'] + const expectedUnsortedItems = ['Євген', 'Віктор', 'Роман'] + const expectedSortedItems = ['Віктор', 'Євген', 'Роман'] - const simple_1 = await payload.create({ - collection: 'simple', - locale: 'uk', - data: { text: 'Роман' }, - }) - const simple_2 = await payload.create({ - collection: 'simple', - locale: 'uk', - data: { text: 'Віктор' }, - }) - const simple_3 = await payload.create({ - collection: 'simple', - locale: 'uk', - data: { text: 'Євген' }, - }) + const simple_1 = await payload.create({ + collection: 'simple', + locale: 'uk', + data: { text: 'Роман' }, + }) + const simple_2 = await payload.create({ + collection: 'simple', + locale: 'uk', + data: { text: 'Віктор' }, + }) + const simple_3 = await payload.create({ + collection: 'simple', + locale: 'uk', + data: { text: 'Євген' }, + }) - const results = await payload.find({ - collection: 'simple', - locale: 'uk', - sort: 'text', - }) + const results = await payload.find({ + collection: 'simple', + locale: 'uk', + sort: 'text', + }) - const initialMappedResults = results.docs.map((doc) => doc.text) + const initialMappedResults = results.docs.map((doc) => doc.text) - expect(initialMappedResults).toEqual(expectedUnsortedItems) + expect(initialMappedResults).toEqual(expectedUnsortedItems) - payload.db.collation = { strength: 1 } + payload.db.collation = { strength: 1 } - const resultsWithCollation = await payload.find({ - collection: 'simple', - locale: 'uk', - sort: 'text', - }) + const resultsWithCollation = await payload.find({ + collection: 'simple', + locale: 'uk', + sort: 'text', + }) - const collatedMappedResults = resultsWithCollation.docs.map((doc) => doc.text) + const collatedMappedResults = resultsWithCollation.docs.map((doc) => doc.text) - console.log({ docs: JSON.stringify(collatedMappedResults) }) + console.log({ docs: JSON.stringify(collatedMappedResults) }) - expect(collatedMappedResults).toEqual(expectedSortedItems) - }) + expect(collatedMappedResults).toEqual(expectedSortedItems) + }, + ) }) diff --git a/test/database/migrations-cli.int.spec.ts b/test/database/migrations-cli.int.spec.ts new file mode 100644 index 00000000000..71b7fa2c74c --- /dev/null +++ b/test/database/migrations-cli.int.spec.ts @@ -0,0 +1,139 @@ +/** + * Standalone CLI migration tests. + * + * These tests verify that predefined migrations are correctly imported and created via the CLI. + * Isolated from the main database tests to avoid connection pool issues since migrateCLI + * creates its own Payload instance internally. + */ +import fs from 'fs' +import path from 'path' +import { migrateCLI } from 'payload' +import { fileURLToPath } from 'url' +import { afterEach, beforeEach, expect } from 'vitest' + +import removeFiles from '../helpers/removeFiles.js' +import { describe, it } from '../helpers/vitest.js' +import configPromise from './config.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +const migrationDir = path.join(dirname, './migrations') + +describe('migrations CLI', () => { + afterEach(() => { + removeFiles(migrationDir) + }) + + beforeEach(() => { + removeFiles(migrationDir) + }) + + it('should create migration from external file path via CLI (plugin predefined migration)', async () => { + // Tests: Absolute file path imports (goes through Path 2 in getPredefinedMigration.ts) + // Example: pnpm payload migrate:create --file /absolute/path/to/migration.ts + + const config = await configPromise + const predefinedMigrationPath = path.join( + dirname, + './predefinedMigrations/testPluginMigration.ts', + ) + + // Use the CLI interface directly, simulating: + // pnpm payload migrate:create --file /path/to/predefinedMigrations/testPluginMigration.ts + await migrateCLI({ + config, + migrationDir, + parsedArgs: { + _: ['migrate:create'], + file: predefinedMigrationPath, + forceAcceptWarning: true, + }, + }) + + // Find the created migration file + const migrationFiles = fs + .readdirSync(migrationDir) + .filter((f) => f.endsWith('.ts') && !f.startsWith('index')) + + expect(migrationFiles.length).toBe(1) + + const migrationContent = fs.readFileSync(path.join(migrationDir, migrationFiles[0]!), 'utf8') + + // Verify the migration contains the predefined SQL from the plugin + expect(migrationContent).toContain('Test predefined migration UP from plugin') + expect(migrationContent).toContain('Test predefined migration DOWN from plugin') + expect(migrationContent).toContain("import { sql } from 'drizzle-orm'") + }) + + it( + 'should create migration from @payloadcms/db-* adapter predefinedMigrations folder', + { db: 'mongo' }, + async () => { + // Tests: Path 1 in getPredefinedMigration.ts - @payloadcms/db-* prefix handling + // These load directly from adapter's predefinedMigrations folder WITHOUT package.json exports + // Example: pnpm payload migrate:create --file @payloadcms/db-mongodb/__testing__ + + const config = await configPromise + + // Use the CLI interface directly, simulating: + // pnpm payload migrate:create --file @payloadcms/db-mongodb/__testing__ + await migrateCLI({ + config, + migrationDir, + parsedArgs: { + _: ['migrate:create'], + file: '@payloadcms/db-mongodb/__testing__', + forceAcceptWarning: true, + }, + }) + + // Find the created migration file + const migrationFiles = fs + .readdirSync(migrationDir) + .filter((f) => f.endsWith('.ts') && !f.startsWith('index')) + expect(migrationFiles.length).toBe(1) + + const migrationContent = fs.readFileSync(path.join(migrationDir, migrationFiles[0]!), 'utf8') + + // Verify the migration contains the predefined content from the package export + expect(migrationContent).toContain( + 'Test predefined migration from @payloadcms/db-mongodb/__testing__', + ) + }, + ) + + it('should create migration from package.json export (non-db package)', async () => { + // Tests: Path 2 in getPredefinedMigration.ts - module specifier via package.json exports + // Packages WITHOUT @payloadcms/db-* prefix MUST use package.json exports + // Example: pnpm payload migrate:create --file payload/__testing__/predefinedMigration + + const config = await configPromise + + // Use the CLI interface directly, simulating: + // pnpm payload migrate:create --file payload/__testing__/predefinedMigration + // payload/__testing__/predefinedMigration is explicitly defined in payload's package.json exports + await migrateCLI({ + config, + migrationDir, + parsedArgs: { + _: ['migrate:create'], + file: 'payload/__testing__/predefinedMigration', + forceAcceptWarning: true, + }, + }) + + // Find the created migration file + const migrationFiles = fs + .readdirSync(migrationDir) + .filter((f) => f.endsWith('.ts') && !f.startsWith('index')) + expect(migrationFiles.length).toBe(1) + + const migrationContent = fs.readFileSync(path.join(migrationDir, migrationFiles[0]!), 'utf8') + + // Verify the migration contains the predefined content from the payload package export + expect(migrationContent).toContain( + 'Test predefined migration from payload/__testing__/predefinedMigration', + ) + }) +}) diff --git a/test/database/payload-types.ts b/test/database/payload-types.ts index f3b0298c56c..df250bcced3 100644 --- a/test/database/payload-types.ts +++ b/test/database/payload-types.ts @@ -126,6 +126,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: ('false' | 'none' | 'null') | false | null | ('en' | 'es' | 'uk') | ('en' | 'es' | 'uk')[]; globals: { header: Header; global: Global; diff --git a/test/database/predefinedMigrations/testPluginMigration.ts b/test/database/predefinedMigrations/testPluginMigration.ts new file mode 100644 index 00000000000..6696a4d4f0b --- /dev/null +++ b/test/database/predefinedMigrations/testPluginMigration.ts @@ -0,0 +1,12 @@ +/** + * Mock predefined migration for testing plugin migration imports. + * This simulates what a plugin would export for its own predefined migrations. + */ +export const upSQL = ` // Test predefined migration UP from plugin + await db.execute(sql\`SELECT 1\`)` + +export const downSQL = ` // Test predefined migration DOWN from plugin + await db.execute(sql\`SELECT 0\`)` + +export const imports = `import { sql } from 'drizzle-orm'` + diff --git a/test/eslint.config.js b/test/eslint.config.js index bef37012cde..68ef706d17d 100644 --- a/test/eslint.config.js +++ b/test/eslint.config.js @@ -36,6 +36,13 @@ export const testEslintConfig = [ }, { files: ['**/*.int.spec.ts', '**/int.spec.ts'], + settings: { + vitest: { + // See https://github.com/vitest-dev/eslint-plugin-vitest?tab=readme-ov-file#custom-fixtures + // This ensures that the eslint plugin recognizes the `it` wrapper function in our helpers/vitest.ts file. + vitestImports: [/helpers\/vitest/], + }, + }, rules: { '@typescript-eslint/no-explicit-any': 'off', }, diff --git a/test/helpers/vitest.ts b/test/helpers/vitest.ts new file mode 100644 index 00000000000..100e829a25b --- /dev/null +++ b/test/helpers/vitest.ts @@ -0,0 +1,93 @@ +import type { SuiteFactory, TestFunction } from 'vitest' + +import { describe as vitestDescribe, it as vitestIt } from 'vitest' + +import { mongooseList } from './isMongoose.js' + +type ItOptions = { + /** Which database adapter(s) this test/suite should run on. Defaults to 'all'. */ + db?: 'all' | 'drizzle' | 'mongo' +} + +const isMongo = mongooseList.includes(process.env.PAYLOAD_DATABASE!) + +/** + * Custom `it` wrapper that supports database-specific test execution. + * + * @example + * // Run only on Drizzle (Postgres/SQLite) + * it('drizzle-specific test', { db: 'drizzle' }, async () => { ... }) + * + * // Run only on MongoDB + * it('mongo-specific test', { db: 'mongo' }, async () => { ... }) + * + * // Run on all databases (default) + * it('universal test', async () => { ... }) + */ +const itWithOptions = ( + name: string, + optionsOrFn?: ItOptions | TestFunction, + fn?: TestFunction, +): ReturnType => { + // Handle overloads: it(name, fn) or it(name, options, fn) + const options: ItOptions | undefined = typeof optionsOrFn === 'object' ? optionsOrFn : undefined + const testFn: TestFunction | undefined = typeof optionsOrFn === 'function' ? optionsOrFn : fn + + const db = options?.db ?? 'all' + + if (db === 'drizzle' && isMongo) { + return vitestIt.skip(name, testFn) + } + if (db === 'mongo' && !isMongo) { + return vitestIt.skip(name, testFn) + } + return vitestIt(name, testFn) +} + +// Add skip property for compatibility +itWithOptions.skip = vitestIt.skip + +// Needs to be called `it` for the vitest vs code extension to recognize it as a test function +export const it = itWithOptions + +/** + * Custom `describe` wrapper that supports database-specific suite execution. + * + * @example + * // Run only on Drizzle (Postgres/SQLite) + * describe('drizzle-specific suite', { db: 'drizzle' }, () => { ... }) + * + * // Run only on MongoDB + * describe('mongo-specific suite', { db: 'mongo' }, () => { ... }) + * + * // Run on all databases (default) + * describe('universal suite', () => { ... }) + */ +const describeWithOptions = ( + name: string, + optionsOrFn?: ItOptions | SuiteFactory, + fn?: SuiteFactory, +): ReturnType => { + // Handle overloads: describe(name, fn) or describe(name, options, fn) + const options: ItOptions | undefined = typeof optionsOrFn === 'object' ? optionsOrFn : undefined + const suiteFn: SuiteFactory | undefined = typeof optionsOrFn === 'function' ? optionsOrFn : fn + + const db = options?.db ?? 'all' + + if (db === 'drizzle' && isMongo) { + return vitestDescribe.skip(name, suiteFn) + } + if (db === 'mongo' && !isMongo) { + return vitestDescribe.skip(name, suiteFn) + } + return vitestDescribe(name, suiteFn) +} + +// Add skip property for compatibility +describeWithOptions.skip = vitestDescribe.skip + +// Needs to be called `describe` for the vitest vs code extension to recognize it +export const describe = describeWithOptions + +// Re-export for convenience +export { isMongo } diff --git a/test/queues/e2e.spec.ts b/test/queues/e2e.spec.ts new file mode 100644 index 00000000000..900d29fa2e2 --- /dev/null +++ b/test/queues/e2e.spec.ts @@ -0,0 +1,142 @@ +import type { APIRequestContext, Page } from '@playwright/test' + +import { expect, test } from '@playwright/test' +import path from 'path' +import { fileURLToPath } from 'url' + +import type { PayloadTestSDK } from '../helpers/sdk/index.js' +import type { Config } from './payload-types.js' + +import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { login } from '../helpers/e2e/auth/login.js' +import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' +import { TEST_TIMEOUT_LONG } from '../playwright.config.js' + +const filename = fileURLToPath(import.meta.url) +const dirname = path.dirname(filename) + +const { beforeAll, beforeEach, describe } = test + +let payload: PayloadTestSDK +let serverURL: string + +describe('Queues', () => { + let page: Page + let apiContext: APIRequestContext + + beforeAll(async ({ browser }, testInfo) => { + testInfo.setTimeout(TEST_TIMEOUT_LONG) + ;({ payload, serverURL } = await initPayloadE2ENoConfig({ dirname })) + + const context = await browser.newContext() + page = await context.newPage() + initPageConsoleErrorCatch(page) + await ensureCompilationIsDone({ page, serverURL }) + + await login({ page, serverURL }) + + // Create an API context that shares cookies with the page + apiContext = context.request + }) + + beforeEach(async () => { + // Clear simple collection before each test + await payload.delete({ + collection: 'simple', + where: { + id: { exists: true }, + }, + }) + + // Clear jobs collection before each test + await payload.delete({ + collection: 'payload-jobs', + where: { + id: { exists: true }, + }, + }) + }) + + describe('External workflow handlers', () => { + /** + * We have the samee tests in int.spec.ts. This is to ensure that the external workflow handlers work correctly in the Next.js bundled environment. + */ + test('can queue and run external workflow with external task handler within Next.js', async () => { + // Queue a job using the externalWorkflow which uses file path handlers + // This tests that dynamic imports work correctly in the Next.js bundled environment + await payload.create({ + collection: 'payload-jobs', + data: { + input: { + message: 'externalWorkflowE2E', + }, + workflowSlug: 'externalWorkflow', + }, + }) + + // Run the job via the jobs endpoint (this runs within Next.js context) + // Using apiContext to make authenticated requests (shares cookies with page) + const runResponse = await apiContext.get(`${serverURL}/api/payload-jobs/run?silent=true`) + expect(runResponse.ok()).toBeTruthy() + + const runResult = await runResponse.json() + expect(runResult.message).toMatch(/success/i) + + // Verify the job was executed by checking if a simple document was created + await expect + .poll( + async () => { + const allSimples = await payload.find({ + collection: 'simple', + limit: 100, + }) + return allSimples.totalDocs + }, + { timeout: 10000 }, + ) + .toBe(1) + + const allSimples = await payload.find({ + collection: 'simple', + limit: 100, + }) + expect(allSimples.docs[0]?.title).toEqual('externalWorkflowE2E') + }) + + test('can queue and run external task with file path handler within Next.js', async () => { + // Queue a task directly using the ExternalTask which uses a file path handler + await payload.create({ + collection: 'payload-jobs', + data: { + input: { + message: 'externalTaskE2E', + }, + taskSlug: 'ExternalTask', + }, + }) + + const runResponse = await apiContext.get(`${serverURL}/api/payload-jobs/run?silent=true`) + expect(runResponse.ok()).toBeTruthy() + + // Verify the job was executed + await expect + .poll( + async () => { + const allSimples = await payload.find({ + collection: 'simple', + limit: 100, + }) + return allSimples.totalDocs + }, + { timeout: 10000 }, + ) + .toBe(1) + + const allSimples = await payload.find({ + collection: 'simple', + limit: 100, + }) + expect(allSimples.docs[0]?.title).toEqual('externalTaskE2E') + }) + }) +}) diff --git a/test/queues/payload-types.ts b/test/queues/payload-types.ts index e399fb6595f..34f847e9ab1 100644 --- a/test/queues/payload-types.ts +++ b/test/queues/payload-types.ts @@ -69,6 +69,7 @@ export interface Config { collections: { posts: Post; simple: Simple; + 'payload-kv': PayloadKv; users: User; 'payload-jobs': PayloadJob; 'payload-locked-documents': PayloadLockedDocument; @@ -79,6 +80,7 @@ export interface Config { collectionsSelect: { posts: PostsSelect | PostsSelect; simple: SimpleSelect | SimpleSelect; + 'payload-kv': PayloadKvSelect | PayloadKvSelect; users: UsersSelect | UsersSelect; 'payload-jobs': PayloadJobsSelect | PayloadJobsSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; @@ -88,6 +90,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: {}; globalsSelect: {}; locale: null; @@ -165,7 +168,7 @@ export interface Post { root: { type: string; children: { - type: string; + type: any; version: number; [k: string]: unknown; }[]; @@ -191,6 +194,23 @@ export interface Simple { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv". + */ +export interface PayloadKv { + id: string; + key: string; + data: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -376,10 +396,6 @@ export interface PayloadLockedDocument { | ({ relationTo: 'users'; value: string | User; - } | null) - | ({ - relationTo: 'payload-jobs'; - value: string | PayloadJob; } | null); globalSlug?: string | null; user: { @@ -444,6 +460,14 @@ export interface SimpleSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv_select". + */ +export interface PayloadKvSelect { + key?: T; + data?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". diff --git a/tools/scripts/src/build-template-with-local-pkgs.ts b/tools/scripts/src/build-template-with-local-pkgs.ts index ea86e749e98..34a6b527cbe 100644 --- a/tools/scripts/src/build-template-with-local-pkgs.ts +++ b/tools/scripts/src/build-template-with-local-pkgs.ts @@ -1,6 +1,6 @@ import { TEMPLATES_DIR } from '@tools/constants' import chalk from 'chalk' -import { execSync } from 'child_process' +import { execSync, spawn } from 'child_process' import fs from 'fs/promises' import path from 'path' @@ -10,12 +10,16 @@ main().catch((error) => { }) async function main() { - const templateName = process.argv[2] + const args = process.argv.slice(2) + const allowWarnings = args.includes('--allow-warnings') + const positionalArgs = args.filter((arg) => !arg.startsWith('--')) + + const templateName = positionalArgs[0] if (!templateName) { throw new Error('Please provide a template name') } const templatePath = path.join(TEMPLATES_DIR, templateName) - const databaseConnection = process.argv[3] || 'mongodb://127.0.0.1/your-database-name' + const databaseConnection = positionalArgs[1] || 'mongodb://127.0.0.1/your-database-name' console.log({ templatePath, @@ -94,7 +98,7 @@ BLOB_READ_WRITE_TOKEN=vercel_blob_rw_TEST_asdf`, execSync('pnpm --ignore-workspace run generate:importmap', execOpts) } - execSync('pnpm --ignore-workspace run build', execOpts) + await runBuildWithWarningsCheck({ cwd: templatePath, allowWarnings }) header(`\n🎉 Done!`) } @@ -103,6 +107,60 @@ function header(message: string, opts?: { enable?: boolean }) { console.log(chalk.bold.green(`${message}\n`)) } +/** + * + * Runs the build command and checks for warnings. If there are any warnings, and the user + * has not allowed them, the build will fail. + * + * This ensures that if any new code introduces warnings in the template build process, it will fail our CI. + * Without this, the warnings will be ignored and the build will pass, even if + * the new code introduces warnings. + */ +async function runBuildWithWarningsCheck(args: { + allowWarnings: boolean + cwd: string +}): Promise { + const { allowWarnings, cwd } = args + + return new Promise((resolve, reject) => { + const buildProcess = spawn('pnpm', ['--ignore-workspace', 'run', 'build'], { + cwd, + shell: true, + }) + + let output = '' + + buildProcess.stdout.on('data', (data: Buffer) => { + process.stdout.write(data) + output += data.toString() + }) + + buildProcess.stderr.on('data', (data: Buffer) => { + process.stderr.write(data) + output += data.toString() + }) + + buildProcess.on('close', (code) => { + if (code !== 0) { + reject(new Error(`Build failed with exit code ${code}`)) + return + } + + if (!allowWarnings && output.includes('Compiled with warnings')) { + console.error( + chalk.red( + '\n❌ Build compiled with warnings. Use --allow-warnings to bypass this check.', + ), + ) + reject(new Error('Build compiled with warnings')) + return + } + + resolve() + }) + }) +} + /** * Recursively updates a JSON object to replace all instances of `workspace:` with the latest version pinned. * From c474572ebd3547aebc9975f3cf57191d0de32e07 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Tue, 23 Dec 2025 08:53:53 -0800 Subject: [PATCH 41/67] test: ensure vitest vscode extension env variables match CI (#15009) Previously, pressing the vitest run button in vs code would run the tests with Node.js type stripping enabled, while running `pnpm test:int` would disable Node.js type stripping. This actually caused some tests to pass locally for me, while they were failing in CI. This PR fixes this by ensuring the vitest vscode extension uses the exact same env variables as the test:int script --- .vscode/settings.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 28630977843..8317ba4ac97 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,5 +21,11 @@ "bun.test.filePattern": "bun.test.ts", "playwright.env": { "NODE_OPTIONS": "--no-deprecation --no-experimental-strip-types" + }, + "vitest.nodeEnv": { + // Ensure the node options match the ones we use for pnpm test:int. Otherwise, the behavior + // of the test run buttons in vscode will be different from CI, which can result to tests passing + // locally, and suddenly failing in CI. + "NODE_OPTIONS": "--no-deprecation --no-experimental-strip-types" } } From 55a35bfe431e1c2c8f51db87c653c1b33bdc5d02 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Tue, 23 Dec 2025 08:54:25 -0800 Subject: [PATCH 42/67] test: fix console logs not appearing on vitest (#15008) We had some legacy jest code in our vitest.setup.console.ts. On jest it was necessary to make console logs more readable - however on vitest this is no longer necessary, in fact it makes the console logs disappear. This PR fixes it by removing that legacy jest code --- test/vitest.setup.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/vitest.setup.ts b/test/vitest.setup.ts index 732a881c8f4..62dafacd18d 100644 --- a/test/vitest.setup.ts +++ b/test/vitest.setup.ts @@ -1,6 +1,3 @@ -import console from 'console' -global.console = console - import dotenv from 'dotenv' dotenv.config() From b660323d1048ec43f53237e00a6944d18afd5ffd Mon Sep 17 00:00:00 2001 From: Riley Langbein <54197972+rilrom@users.noreply.github.com> Date: Tue, 30 Dec 2025 10:05:15 +1030 Subject: [PATCH 43/67] fix: add beforeDocumentControls to globals generate importmap (#15036) ### What? When adding `beforeDocumentControls` as a custom component to a global, it does not get picked up by the import map, even when running `generate:importmap`. ### Why? `beforeDocumentControls` is missing from `addToImportMap` in `iterateGlobals`. ### How? Adds `beforeDocumentControls` to `addToImportMap` in `iterateGlobals`. While doing this I've used the opportunity to add `Description` to the globals custom component documentation as it was missing. Fixes #15035 Co-authored-by: Riley Langbein --- docs/configuration/globals.mdx | 14 ++++++++------ .../src/bin/generateImportMap/iterateGlobals.ts | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/configuration/globals.mdx b/docs/configuration/globals.mdx index d8eaa561113..e8db8fc225e 100644 --- a/docs/configuration/globals.mdx +++ b/docs/configuration/globals.mdx @@ -179,12 +179,14 @@ export const MyGlobal: SanitizedGlobalConfig = { The following options are available: -| Option | Description | -| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `SaveButton` | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. [More details](../custom-components/edit-view#savebutton). | -| `SaveDraftButton` | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. [More details](../custom-components/edit-view#savedraftbutton). | -| `PublishButton` | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. [More details](../custom-components/edit-view#publishbutton). | -| `PreviewButton` | Replace the default Preview Button with a Custom Component. [Preview](../admin/preview) must be enabled. [More details](../custom-components/edit-view#previewbutton). | +| Option | Description | +| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `beforeDocumentControls` | Inject custom components before the Save button. [More details](../custom-components/edit-view#beforedocumentcontrols). | +| `Description` | A component to render below the Global label in the Edit View. [More details](../custom-components/edit-view#description). | +| `SaveButton` | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. [More details](../custom-components/edit-view#savebutton). | +| `SaveDraftButton` | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. [More details](../custom-components/edit-view#savedraftbutton). | +| `PublishButton` | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. [More details](../custom-components/edit-view#publishbutton). | +| `PreviewButton` | Replace the default Preview Button with a Custom Component. [Preview](../admin/preview) must be enabled. [More details](../custom-components/edit-view#previewbutton). | **Note:** For details on how to build Custom Components, see [Building Custom diff --git a/packages/payload/src/bin/generateImportMap/iterateGlobals.ts b/packages/payload/src/bin/generateImportMap/iterateGlobals.ts index 366b27eca42..a6728915695 100644 --- a/packages/payload/src/bin/generateImportMap/iterateGlobals.ts +++ b/packages/payload/src/bin/generateImportMap/iterateGlobals.ts @@ -29,6 +29,7 @@ export function iterateGlobals({ imports, }) + addToImportMap(global.admin?.components?.elements?.beforeDocumentControls) addToImportMap(global.admin?.components?.elements?.Description) addToImportMap(global.admin?.components?.elements?.PreviewButton) addToImportMap(global.admin?.components?.elements?.PublishButton) From 03aee813b1d50a5f2eed17ff3ce66ac6482fee8f Mon Sep 17 00:00:00 2001 From: Riley Langbein <54197972+rilrom@users.noreply.github.com> Date: Wed, 31 Dec 2025 06:04:58 +1030 Subject: [PATCH 44/67] chore(claude): fix typo in claude skills access control advanced file (#15060) Fixes #15056. --- .../skills/payload/reference/ACCESS-CONTROL-ADVANCED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/claude-plugin/skills/payload/reference/ACCESS-CONTROL-ADVANCED.md b/tools/claude-plugin/skills/payload/reference/ACCESS-CONTROL-ADVANCED.md index 77da117acd7..557e3e66da6 100644 --- a/tools/claude-plugin/skills/payload/reference/ACCESS-CONTROL-ADVANCED.md +++ b/tools/claude-plugin/skills/payload/reference/ACCESS-CONTROL-ADVANCED.md @@ -67,7 +67,7 @@ export const MobileContent: CollectionConfig = { Restrict access from specific IP addresses (requires middleware/proxy headers). ```ts -import type: Access } from 'payload' +import type { Access } from 'payload' export const restrictedIpAccess = (allowedIps: string[]): Access => { return ({ req: { headers } }) => { From ef8237f38652e24e8afc46bc4440d1dd9098de73 Mon Sep 17 00:00:00 2001 From: Anders Semb Hermansen Date: Tue, 30 Dec 2025 22:46:47 +0100 Subject: [PATCH 45/67] feat: support qs-esm sort arrays in REST API (#15065) ### What? Support qs-esm array in sort parameter to sort by multiple columns in REST API ### Why? To align input of Local API and REST API so that REST API also accepts array like Local API do. ### How? Extract parsing/sanitizing of sort input to it's own method which also accept array. Added unit and integration test. Updated docs with example. Fixes #15052 --- docs/queries/sort.mdx | 21 +++++++++++++++++++ .../src/globals/endpoints/findVersions.ts | 5 +++-- .../src/utilities/parseParams/index.spec.ts | 18 ++++++++++++++++ .../src/utilities/parseParams/index.ts | 7 ++++--- .../src/utilities/sanitizeSortParams.ts | 11 ++++++++++ test/sort/int.spec.ts | 18 ++++++++++++++++ 6 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 packages/payload/src/utilities/sanitizeSortParams.ts diff --git a/docs/queries/sort.mdx b/docs/queries/sort.mdx index 5ff67f58216..a209820b85c 100644 --- a/docs/queries/sort.mdx +++ b/docs/queries/sort.mdx @@ -67,6 +67,27 @@ fetch('https://localhost:3000/api/posts?sort=priority,-createdAt') // highlight- .then((data) => console.log(data)) ``` +You can also pass `sort` as an array so each item is a single field when using query string builder: + +```ts +import { stringify } from 'qs-esm' + +const getPosts = async () => { + const stringifiedQuery = stringify( + { + sort: ['priority', '-createdAt'], + }, + { addQueryPrefix: true }, + ) + + const response = await fetch( + `https://localhost:3000/api/posts${stringifiedQuery}`, // highlight-line + ) + const data = await response.json() + return data +} +``` + ## GraphQL API To sort in the [GraphQL API](../graphql/overview), you can use the `sort` parameter in your query: diff --git a/packages/payload/src/globals/endpoints/findVersions.ts b/packages/payload/src/globals/endpoints/findVersions.ts index 2f2c25b2289..902fdb9e331 100644 --- a/packages/payload/src/globals/endpoints/findVersions.ts +++ b/packages/payload/src/globals/endpoints/findVersions.ts @@ -8,6 +8,7 @@ import { headersWithCors } from '../../utilities/headersWithCors.js' import { isNumber } from '../../utilities/isNumber.js' import { sanitizePopulateParam } from '../../utilities/sanitizePopulateParam.js' import { sanitizeSelectParam } from '../../utilities/sanitizeSelectParam.js' +import { sanitizeSortParams } from '../../utilities/sanitizeSortParams.js' import { findVersionsOperation } from '../operations/findVersions.js' export const findVersionsHandler: PayloadHandler = async (req) => { @@ -19,7 +20,7 @@ export const findVersionsHandler: PayloadHandler = async (req) => { pagination?: string populate?: Record select?: Record - sort?: string + sort?: string | string[] where?: Where } @@ -32,7 +33,7 @@ export const findVersionsHandler: PayloadHandler = async (req) => { populate: sanitizePopulateParam(populate), req, select: sanitizeSelectParam(select), - sort: typeof sort === 'string' ? sort.split(',') : undefined, + sort: sanitizeSortParams(sort), where, }) diff --git a/packages/payload/src/utilities/parseParams/index.spec.ts b/packages/payload/src/utilities/parseParams/index.spec.ts index 14eaa1774d0..49b4f402e6e 100644 --- a/packages/payload/src/utilities/parseParams/index.spec.ts +++ b/packages/payload/src/utilities/parseParams/index.spec.ts @@ -1,3 +1,4 @@ +import * as qs from 'qs-esm' import { describe, it, expect } from 'vitest' import { parseParams, booleanParams, numberParams } from './index.js' @@ -105,11 +106,28 @@ describe('parseParams', () => { expect(result.sort).toEqual(['name', ' createdAt ', ' -updatedAt']) }) + it('should parse array of strings', () => { + const result = parseParams({ sort: ['name', '-createdAt'] }) + expect(result.sort).toEqual(['name', '-createdAt']) + }) + it('should return undefined for non-string sort values', () => { const result = parseParams({ sort: 123 as any }) expect(result.sort).toBeUndefined() }) + it('should return undefined for array with non-string sort values', () => { + const result = parseParams({ sort: ['name', 123] as any }) + expect(result.sort).toBeUndefined() + }) + + it('should handle qs-esm array sort parsing', () => { + const query = qs.stringify({ sort: ['title', '-createdAt'] }) + const parsed = qs.parse(query) + const result = parseParams(parsed) + expect(result.sort).toEqual(['title', '-createdAt']) + }) + it('should return undefined for null sort values', () => { const result = parseParams({ sort: null as any }) expect(result.sort).toBeUndefined() diff --git a/packages/payload/src/utilities/parseParams/index.ts b/packages/payload/src/utilities/parseParams/index.ts index fcacfe71347..617ab958452 100644 --- a/packages/payload/src/utilities/parseParams/index.ts +++ b/packages/payload/src/utilities/parseParams/index.ts @@ -6,6 +6,7 @@ import { parseBooleanString } from '../parseBooleanString.js' import { sanitizeJoinParams } from '../sanitizeJoinParams.js' import { sanitizePopulateParam } from '../sanitizePopulateParam.js' import { sanitizeSelectParam } from '../sanitizeSelectParam.js' +import { sanitizeSortParams } from '../sanitizeSortParams.js' type ParsedParams = { autosave?: boolean @@ -45,7 +46,7 @@ type RawParams = { publishSpecificLocale?: string select?: unknown selectedLocales?: string - sort?: string + sort?: string | string[] trash?: string where?: Where } @@ -66,7 +67,7 @@ export const numberParams = ['depth', 'limit', 'page'] * Examples: * a. `draft` provided as a string of "true" is converted to a boolean * b. `depth` provided as a string of "0" is converted to a number - * c. `sort` provided as a comma-separated string is converted to an array of strings + * c. `sort` provided as a comma-separated string or array is converted to an array of strings */ export const parseParams = (params: RawParams): ParsedParams => { const parsedParams = (params || {}) as ParsedParams @@ -99,7 +100,7 @@ export const parseParams = (params: RawParams): ParsedParams => { } if ('sort' in params) { - parsedParams.sort = typeof params.sort === 'string' ? params.sort.split(',') : undefined + parsedParams.sort = sanitizeSortParams(params.sort) } if ('data' in params && typeof params.data === 'string' && params.data.length > 0) { diff --git a/packages/payload/src/utilities/sanitizeSortParams.ts b/packages/payload/src/utilities/sanitizeSortParams.ts new file mode 100644 index 00000000000..ef543315e54 --- /dev/null +++ b/packages/payload/src/utilities/sanitizeSortParams.ts @@ -0,0 +1,11 @@ +export const sanitizeSortParams = (sort: unknown): string[] | undefined => { + if (typeof sort === 'string') { + return sort.split(',') + } + + if (Array.isArray(sort) && sort.every((value) => typeof value === 'string')) { + return sort + } + + return undefined +} diff --git a/test/sort/int.spec.ts b/test/sort/int.spec.ts index 1512c0a8ec7..a088968a143 100644 --- a/test/sort/int.spec.ts +++ b/test/sort/int.spec.ts @@ -1,6 +1,7 @@ import type { CollectionSlug, Payload } from 'payload' import path from 'path' +import * as qs from 'qs-esm' import { fileURLToPath } from 'url' import { afterAll, beforeAll, describe, expect, it } from 'vitest' @@ -915,6 +916,23 @@ describe('Sort', () => { ]) }) }) + + describe('Sort by multiple fields as array', () => { + it('should sort posts by multiple fields using qs-esm array params', async () => { + const query = qs.stringify({ sort: ['number2', '-number'] }) + + const res = await restClient.GET(`/posts?${query}`).then((res) => res.json()) + + expect(res.docs.map((post) => post.text)).toEqual([ + 'Post 10', // 5, 10 + 'Post 3', // 5, 3 + 'Post 2', // 10, 2 + 'Post 1', // 10, 1 + 'Post 12', // 20, 12 + 'Post 11', // 20, 11 + ]) + }) + }) }) }) From 0e13ac487151eea94cddbe00476d3b3905480d57 Mon Sep 17 00:00:00 2001 From: Patrikbjoh <115511376+Patrikbjoh@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:35:27 +0100 Subject: [PATCH 46/67] chore: bump nodemailer to 7.0.12 (security) (#15062) Bumps nodemailer to 7.0.12 in packages/email-nodemailer to include recent security fixes. This should address the advisory flagged by pnpm audit. I ran local tests and builds. Happy to iterate if you prefer a different target. fixes https://github.com/payloadcms/payload/issues/15061 --------- Co-authored-by: Dan Ribbens --- packages/email-nodemailer/package.json | 2 +- packages/payload-cloud/package.json | 2 +- pnpm-lock.yaml | 28 +++++++++++--------------- test/package.json | 2 +- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/packages/email-nodemailer/package.json b/packages/email-nodemailer/package.json index 26e24c6e467..c16a6fcf584 100644 --- a/packages/email-nodemailer/package.json +++ b/packages/email-nodemailer/package.json @@ -42,7 +42,7 @@ "lint:fix": "eslint . --fix" }, "dependencies": { - "nodemailer": "7.0.9" + "nodemailer": "7.0.12" }, "devDependencies": { "@types/nodemailer": "7.0.2", diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index 155cdd15f9a..fe6a9f8f6fb 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -48,7 +48,7 @@ "@aws-sdk/lib-storage": "^3.614.0", "@payloadcms/email-nodemailer": "workspace:*", "amazon-cognito-identity-js": "^6.1.2", - "nodemailer": "7.0.9" + "nodemailer": "7.0.12" }, "devDependencies": { "@types/nodemailer": "7.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 93513912f94..b4640e4fb79 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -530,8 +530,8 @@ importers: packages/email-nodemailer: dependencies: nodemailer: - specifier: 7.0.9 - version: 7.0.9 + specifier: 7.0.12 + version: 7.0.12 devDependencies: '@types/nodemailer': specifier: 7.0.2 @@ -1026,8 +1026,8 @@ importers: specifier: ^6.1.2 version: 6.3.12 nodemailer: - specifier: 7.0.9 - version: 7.0.9 + specifier: 7.0.12 + version: 7.0.12 devDependencies: '@types/nodemailer': specifier: 7.0.2 @@ -1850,7 +1850,7 @@ importers: version: 16.8.1 next: specifier: 15.4.10 - version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: workspace:* version: link:../../packages/payload @@ -1992,7 +1992,7 @@ importers: version: 8.6.0(react@19.2.1) geist: specifier: ^1.3.0 - version: 1.4.2(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) graphql: specifier: 16.8.1 version: 16.8.1 @@ -2004,7 +2004,7 @@ importers: version: 0.477.0(react@19.2.1) next: specifier: 15.4.10 - version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes: specifier: 0.4.6 version: 0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -2516,8 +2516,8 @@ importers: specifier: 15.4.10 version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) nodemailer: - specifier: 7.0.9 - version: 7.0.9 + specifier: 7.0.12 + version: 7.0.12 object-to-formdata: specifier: 4.5.1 version: 4.5.1 @@ -11875,8 +11875,8 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - nodemailer@7.0.9: - resolution: {integrity: sha512-9/Qm0qXIByEP8lEV2qOqcAW7bRpL8CR9jcTwk3NBnHJNmP9fIJ86g2fgmIXqHY+nj55ZEMwWqYAT2QTDpRUYiQ==} + nodemailer@7.0.12: + resolution: {integrity: sha512-H+rnK5bX2Pi/6ms3sN4/jRQvYSMltV6vqup/0SFOrxYYY/qoNvhXPlYq3e+Pm9RFJRwrMGbMIwi81M4dxpomhA==} engines: {node: '>=6.0.0'} noms@0.0.0: @@ -24464,10 +24464,6 @@ snapshots: - encoding - supports-color - geist@1.4.2(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): - dependencies: - next: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) - geist@1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) @@ -26220,7 +26216,7 @@ snapshots: node-releases@2.0.19: {} - nodemailer@7.0.9: {} + nodemailer@7.0.12: {} noms@0.0.0: dependencies: diff --git a/test/package.json b/test/package.json index 965d2b824e7..af6a983a8b1 100644 --- a/test/package.json +++ b/test/package.json @@ -96,7 +96,7 @@ "jwt-decode": "4.0.0", "mongoose": "8.15.1", "next": "15.4.10", - "nodemailer": "7.0.9", + "nodemailer": "7.0.12", "object-to-formdata": "4.5.1", "payload": "workspace:*", "pg": "8.16.3", From d1e083ec167f069ac51dbe8051a3071560179c15 Mon Sep 17 00:00:00 2001 From: Jonathan Elmgren <81702447+jonathanelmgren@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:39:04 +0100 Subject: [PATCH 47/67] fix(plugin-mcp): pin modelcontextprotocol/sdk dependency version to 1.24.0 (#15017) ## Summary Pins `@modelcontextprotocol/sdk` to `~1.24.0` to avoid breaking changes in 1.25.x that cause 406 errors in the MCP plugin. ## Problem The current dependency declaration `^1.17.2` allows installation of `@modelcontextprotocol/sdk@1.25.x`, which introduced breaking changes in the `WebStandardStreamableHTTPServerTransport` that cause the MCP plugin to fail with 406 "Not Acceptable" errors. ## Solution Change the dependency to use `~1.24.0` (tilde) instead of `^1.17.2` (caret), restricting updates to patch versions only (1.24.x). ## Changes - `packages/plugin-mcp/package.json`: Update SDK version from `^1.17.2` to `~1.24.0` ## Breaking Changes None - this prevents a breaking change from affecting users. ## Follow-up Once the @modelcontextprotocol/sdk team releases a fixed version or documents the correct usage pattern for 1.25.x+, we can update to allow newer versions. closes: [#15016](https://github.com/payloadcms/payload/issues/15018) closes: #14952 --- packages/plugin-mcp/package.json | 2 +- pnpm-lock.yaml | 23 +++++++++++------------ 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/plugin-mcp/package.json b/packages/plugin-mcp/package.json index 2793bfb941b..f9181038e2a 100644 --- a/packages/plugin-mcp/package.json +++ b/packages/plugin-mcp/package.json @@ -48,7 +48,7 @@ "pack:plugin": "pnpm build && pnpm pack" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.17.2", + "@modelcontextprotocol/sdk": "~1.24.0", "@types/json-schema": "7.0.15", "@vercel/mcp-adapter": "^1.0.0", "json-schema-to-zod": "2.6.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4640e4fb79..ddb9c3fe35b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1175,7 +1175,7 @@ importers: packages/plugin-mcp: dependencies: '@modelcontextprotocol/sdk': - specifier: ^1.17.2 + specifier: ~1.24.0 version: 1.24.3(zod@3.25.76) '@types/json-schema': specifier: 7.0.15 @@ -11818,7 +11818,6 @@ packages: next@15.5.4: resolution: {integrity: sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} - deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -17167,7 +17166,7 @@ snapshots: '@babel/parser': 7.27.5 '@babel/template': 7.27.2 '@babel/types': 7.27.3 - debug: 4.4.1 + debug: 4.4.3 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -22168,13 +22167,13 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color agent-base@7.1.1: dependencies: - debug: 4.4.1 + debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -22520,7 +22519,7 @@ snapshots: dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 4.4.1 + debug: 4.4.3 http-errors: 2.0.0 iconv-lite: 0.6.3 on-finished: 2.4.1 @@ -24106,7 +24105,7 @@ snapshots: execa@8.0.1: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 get-stream: 8.0.1 human-signals: 5.0.0 is-stream: 3.0.0 @@ -24283,7 +24282,7 @@ snapshots: finalhandler@2.1.0: dependencies: - debug: 4.4.1 + debug: 4.4.3 encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -24353,7 +24352,7 @@ snapshots: foreground-child@3.3.0: dependencies: - cross-spawn: 7.0.5 + cross-spawn: 7.0.6 signal-exit: 4.1.0 form-data-encoder@1.7.2: {} @@ -27136,7 +27135,7 @@ snapshots: require-in-the-middle@7.4.0: dependencies: - debug: 4.4.1 + debug: 4.4.3 module-details-from-path: 1.0.3 resolve: 1.22.8 transitivePeerDependencies: @@ -27246,7 +27245,7 @@ snapshots: router@2.2.0: dependencies: - debug: 4.4.1 + debug: 4.4.3 depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -27461,7 +27460,7 @@ snapshots: send@1.2.0: dependencies: - debug: 4.4.1 + debug: 4.4.3 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 From 9c910a0729ba4b3fd4f6572ab62fd27a2c9e815d Mon Sep 17 00:00:00 2001 From: Jessica Rynkar <67977755+jessrynkar@users.noreply.github.com> Date: Mon, 5 Jan 2026 16:29:35 +0000 Subject: [PATCH 48/67] fix: s3 plugin uploads files before validation (#14988) ### What Fixes issue with `plugin-cloud-storage` where invalid files are still passed to the storage adapter. ### Why Files are uploaded to external storage via the `beforeChange` hook, which runs before field-level validation. Therefore, even if a file fails validation, it has already been uploaded to the external storage, resulting in orphaned files. ### How - Moved upload logic from `beforeChange` to `afterChange` hook in `plugin-cloud-storage` - Added int tests to verify behavior # Important This change moves the external file uploading process from `beforeChange` to the `afterChange` hook in the S3 plugin. It may break custom code that overrides the `beforeChange` hook and expects files to be uploaded earlier. Standard usage without overrides is unaffected. --- .../hooks/{beforeChange.ts => afterChange.ts} | 30 +++---- packages/plugin-cloud-storage/src/plugin.ts | 10 +-- .../collections/RestrictedMedia.ts | 15 ++++ test/plugin-cloud-storage/config.ts | 8 +- test/plugin-cloud-storage/int.spec.ts | 44 +++++++++- test/plugin-cloud-storage/payload-types.ts | 85 +++++++++++++++++++ test/plugin-cloud-storage/shared.ts | 1 + test/plugin-cloud-storage/test.json | 14 +++ tsconfig.base.json | 2 +- 9 files changed, 185 insertions(+), 24 deletions(-) rename packages/plugin-cloud-storage/src/hooks/{beforeChange.ts => afterChange.ts} (60%) create mode 100644 test/plugin-cloud-storage/collections/RestrictedMedia.ts create mode 100644 test/plugin-cloud-storage/test.json diff --git a/packages/plugin-cloud-storage/src/hooks/beforeChange.ts b/packages/plugin-cloud-storage/src/hooks/afterChange.ts similarity index 60% rename from packages/plugin-cloud-storage/src/hooks/beforeChange.ts rename to packages/plugin-cloud-storage/src/hooks/afterChange.ts index c2aa74484be..938b61f15dd 100644 --- a/packages/plugin-cloud-storage/src/hooks/beforeChange.ts +++ b/packages/plugin-cloud-storage/src/hooks/afterChange.ts @@ -1,4 +1,4 @@ -import type { CollectionBeforeChangeHook, CollectionConfig, FileData, TypeWithID } from 'payload' +import type { CollectionAfterChangeHook, CollectionConfig, FileData, TypeWithID } from 'payload' import type { GeneratedAdapter } from '../types.js' @@ -9,26 +9,26 @@ interface Args { collection: CollectionConfig } -export const getBeforeChangeHook = - ({ adapter, collection }: Args): CollectionBeforeChangeHook => - async ({ data, originalDoc, req }) => { +export const getAfterChangeHook = + ({ adapter, collection }: Args): CollectionAfterChangeHook => + async ({ doc, previousDoc, req }) => { try { - const files = getIncomingFiles({ data, req }) + const files = getIncomingFiles({ data: doc, req }) if (files.length > 0) { - // If there is an original doc, + // If there is a previous doc, // And we have new files, // We need to delete the old files before uploading new - if (originalDoc) { + if (previousDoc) { let filesToDelete: string[] = [] - if (typeof originalDoc?.filename === 'string') { - filesToDelete.push(originalDoc.filename) + if (typeof previousDoc?.filename === 'string') { + filesToDelete.push(previousDoc.filename) } - if (typeof originalDoc.sizes === 'object') { + if (typeof previousDoc.sizes === 'object') { filesToDelete = filesToDelete.concat( - Object.values(originalDoc?.sizes || []).map( + Object.values(previousDoc?.sizes || []).map( (resizedFileData) => resizedFileData?.filename as string, ), ) @@ -36,7 +36,7 @@ export const getBeforeChangeHook = const deletionPromises = filesToDelete.map(async (filename) => { if (filename) { - await adapter.handleDelete({ collection, doc: originalDoc, filename, req }) + await adapter.handleDelete({ collection, doc: previousDoc, filename, req }) } }) @@ -47,7 +47,7 @@ export const getBeforeChangeHook = await adapter.handleUpload({ clientUploadContext: file.clientUploadContext, collection, - data, + data: doc, file, req, }) @@ -57,10 +57,10 @@ export const getBeforeChangeHook = } } catch (err: unknown) { req.payload.logger.error( - `There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${data.filename}:`, + `There was an error while uploading files corresponding to the collection ${collection.slug} with filename ${doc.filename}:`, ) req.payload.logger.error({ err }) throw err } - return data + return doc } diff --git a/packages/plugin-cloud-storage/src/plugin.ts b/packages/plugin-cloud-storage/src/plugin.ts index 1d0bacbe502..4f25c7fda1b 100644 --- a/packages/plugin-cloud-storage/src/plugin.ts +++ b/packages/plugin-cloud-storage/src/plugin.ts @@ -3,8 +3,8 @@ import type { Config } from 'payload' import type { AllowList, PluginOptions } from './types.js' import { getFields } from './fields/getFields.js' +import { getAfterChangeHook } from './hooks/afterChange.js' import { getAfterDeleteHook } from './hooks/afterDelete.js' -import { getBeforeChangeHook } from './hooks/beforeChange.js' // This plugin extends all targeted collections by offloading uploaded files // to cloud storage instead of solely storing files locally. @@ -116,14 +116,14 @@ export const cloudStoragePlugin = fields, hooks: { ...(existingCollection.hooks || {}), + afterChange: [ + ...(existingCollection.hooks?.afterChange || []), + getAfterChangeHook({ adapter, collection: existingCollection }), + ], afterDelete: [ ...(existingCollection.hooks?.afterDelete || []), getAfterDeleteHook({ adapter, collection: existingCollection }), ], - beforeChange: [ - ...(existingCollection.hooks?.beforeChange || []), - getBeforeChangeHook({ adapter, collection: existingCollection }), - ], }, upload: { ...(typeof existingCollection.upload === 'object' ? existingCollection.upload : {}), diff --git a/test/plugin-cloud-storage/collections/RestrictedMedia.ts b/test/plugin-cloud-storage/collections/RestrictedMedia.ts new file mode 100644 index 00000000000..aa223ac7f02 --- /dev/null +++ b/test/plugin-cloud-storage/collections/RestrictedMedia.ts @@ -0,0 +1,15 @@ +import type { CollectionConfig } from 'payload' + +export const RestrictedMedia: CollectionConfig = { + slug: 'restricted-media', + upload: { + mimeTypes: ['image/png'], + disableLocalStorage: true, + }, + fields: [ + { + name: 'title', + type: 'text', + }, + ], +} diff --git a/test/plugin-cloud-storage/config.ts b/test/plugin-cloud-storage/config.ts index ba24aa10e0c..00da08ddccb 100644 --- a/test/plugin-cloud-storage/config.ts +++ b/test/plugin-cloud-storage/config.ts @@ -11,8 +11,9 @@ import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { devUser } from '../credentials.js' import { Media } from './collections/Media.js' import { MediaWithPrefix } from './collections/MediaWithPrefix.js' +import { RestrictedMedia } from './collections/RestrictedMedia.js' import { Users } from './collections/Users.js' -import { mediaSlug, mediaWithPrefixSlug, prefix } from './shared.js' +import { mediaSlug, mediaWithPrefixSlug, restrictedMediaSlug, prefix } from './shared.js' import { createTestBucket } from './utils.js' const filename = fileURLToPath(import.meta.url) @@ -33,6 +34,7 @@ if (process.env.PAYLOAD_PUBLIC_CLOUD_STORAGE_ADAPTER === 'azure') { [mediaWithPrefixSlug]: { prefix, }, + [restrictedMediaSlug]: true, }, allowContainerCreate: process.env.AZURE_STORAGE_ALLOW_CONTAINER_CREATE === 'true', baseURL: process.env.AZURE_STORAGE_ACCOUNT_BASEURL, @@ -48,6 +50,7 @@ if (process.env.PAYLOAD_PUBLIC_CLOUD_STORAGE_ADAPTER === 'gcs') { [mediaWithPrefixSlug]: { prefix, }, + [restrictedMediaSlug]: true, }, bucket: process.env.GCS_BUCKET, options: { @@ -72,6 +75,7 @@ if ( [mediaWithPrefixSlug]: { prefix, }, + [restrictedMediaSlug]: true, }, bucket: process.env.S3_BUCKET, config: { @@ -113,7 +117,7 @@ export default buildConfigWithDefaults({ baseDir: path.resolve(dirname), }, }, - collections: [Media, MediaWithPrefix, Users], + collections: [Media, MediaWithPrefix, RestrictedMedia, Users], onInit: async (payload) => { /*const client = new AWS.S3({ endpoint: process.env.S3_ENDPOINT, diff --git a/test/plugin-cloud-storage/int.spec.ts b/test/plugin-cloud-storage/int.spec.ts index a5e29a4bd65..0bdb2a34292 100644 --- a/test/plugin-cloud-storage/int.spec.ts +++ b/test/plugin-cloud-storage/int.spec.ts @@ -10,7 +10,7 @@ import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest' import type { Config } from './payload-types.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' -import { mediaSlug, mediaWithPrefixSlug, prefix } from './shared.js' +import { mediaSlug, mediaWithPrefixSlug, prefix, restrictedMediaSlug } from './shared.js' import { clearTestBucket, createTestBucket } from './utils.js' const filename = fileURLToPath(import.meta.url) @@ -104,6 +104,48 @@ describe('@payloadcms/plugin-cloud-storage', () => { }) expect(upload.url).toEqual(`/api/${mediaWithPrefixSlug}/file/${String(upload.filename)}`) }) + + it('should not upload to S3 when mimeType validation fails', async () => { + // Get initial bucket contents + const listBefore = await client.send(new AWS.ListObjectsV2Command({ Bucket: TEST_BUCKET })) + const fileCountBefore = listBefore.Contents?.length || 0 + + // Try to upload a JSON file to a collection that only accepts PNG + await expect( + payload.create({ + collection: restrictedMediaSlug, + data: {}, + filePath: path.resolve(dirname, './test.json'), + }), + ).rejects.toThrow() + + // Verify no new files were uploaded to S3 + const listAfter = await client.send(new AWS.ListObjectsV2Command({ Bucket: TEST_BUCKET })) + const fileCountAfter = listAfter.Contents?.length || 0 + + expect(fileCountAfter).toBe(fileCountBefore) + }) + + it('should upload to S3 when mimeType validation passes', async () => { + // Upload a valid PNG file + const upload = await payload.create({ + collection: restrictedMediaSlug, + data: {}, + filePath: path.resolve(dirname, './image.png'), + }) + + expect(upload.id).toBeTruthy() + + // Verify the file was uploaded to S3 + const { $metadata } = await client.send( + new AWS.HeadObjectCommand({ + Bucket: TEST_BUCKET, + Key: upload.filename, + }), + ) + + expect($metadata.httpStatusCode).toBe(200) + }) }) }) diff --git a/test/plugin-cloud-storage/payload-types.ts b/test/plugin-cloud-storage/payload-types.ts index 7311e4ebb9e..b93b9eba761 100644 --- a/test/plugin-cloud-storage/payload-types.ts +++ b/test/plugin-cloud-storage/payload-types.ts @@ -69,7 +69,9 @@ export interface Config { collections: { media: Media; 'media-with-prefix': MediaWithPrefix; + 'restricted-media': RestrictedMedia; users: User; + 'payload-kv': PayloadKv; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; 'payload-migrations': PayloadMigration; @@ -78,7 +80,9 @@ export interface Config { collectionsSelect: { media: MediaSelect | MediaSelect; 'media-with-prefix': MediaWithPrefixSelect | MediaWithPrefixSelect; + 'restricted-media': RestrictedMediaSelect | RestrictedMediaSelect; users: UsersSelect | UsersSelect; + 'payload-kv': PayloadKvSelect | PayloadKvSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; @@ -86,6 +90,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: {}; globalsSelect: {}; locale: null; @@ -171,6 +176,25 @@ export interface MediaWithPrefix { focalX?: number | null; focalY?: number | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "restricted-media". + */ +export interface RestrictedMedia { + id: string; + title?: string | null; + updatedAt: string; + createdAt: string; + url?: string | null; + thumbnailURL?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + focalX?: number | null; + focalY?: number | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -186,8 +210,32 @@ export interface User { hash?: string | null; loginAttempts?: number | null; lockUntil?: string | null; + sessions?: + | { + id: string; + createdAt?: string | null; + expiresAt: string; + }[] + | null; password?: string | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv". + */ +export interface PayloadKv { + id: string; + key: string; + data: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-locked-documents". @@ -203,6 +251,10 @@ export interface PayloadLockedDocument { relationTo: 'media-with-prefix'; value: string | MediaWithPrefix; } | null) + | ({ + relationTo: 'restricted-media'; + value: string | RestrictedMedia; + } | null) | ({ relationTo: 'users'; value: string | User; @@ -309,6 +361,24 @@ export interface MediaWithPrefixSelect { focalX?: T; focalY?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "restricted-media_select". + */ +export interface RestrictedMediaSelect { + title?: T; + updatedAt?: T; + createdAt?: T; + url?: T; + thumbnailURL?: T; + filename?: T; + mimeType?: T; + filesize?: T; + width?: T; + height?: T; + focalX?: T; + focalY?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". @@ -323,6 +393,21 @@ export interface UsersSelect { hash?: T; loginAttempts?: T; lockUntil?: T; + sessions?: + | T + | { + id?: T; + createdAt?: T; + expiresAt?: T; + }; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv_select". + */ +export interface PayloadKvSelect { + key?: T; + data?: T; } /** * This interface was referenced by `Config`'s JSON-Schema diff --git a/test/plugin-cloud-storage/shared.ts b/test/plugin-cloud-storage/shared.ts index 7d74b323ae4..e4d58d3b1d1 100644 --- a/test/plugin-cloud-storage/shared.ts +++ b/test/plugin-cloud-storage/shared.ts @@ -1,3 +1,4 @@ export const mediaSlug = 'media' export const mediaWithPrefixSlug = 'media-with-prefix' +export const restrictedMediaSlug = 'restricted-media' export const prefix = 'test-prefix' diff --git a/test/plugin-cloud-storage/test.json b/test/plugin-cloud-storage/test.json new file mode 100644 index 00000000000..2314d84c0b1 --- /dev/null +++ b/test/plugin-cloud-storage/test.json @@ -0,0 +1,14 @@ +{ + "users": [ + { + "name": "John Doe", + "email": "john@example.com", + "age": 30 + }, + { + "name": "Jane Smith", + "email": "jane@example.com", + "age": 25 + } + ] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 4ea13ef00ca..f6fc213b7b1 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -95,4 +95,4 @@ }, "include": ["${configDir}/src"], "exclude": ["${configDir}/dist", "${configDir}/build", "${configDir}/temp", "**/*.spec.ts"] -} +} \ No newline at end of file From d2f24fb31326e58f69452c5f3805d4820c1ad8ee Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 5 Jan 2026 11:55:14 -0600 Subject: [PATCH 49/67] fix(storage-*): allow prefix to always exist as a field via alwaysInsertFields flag (#14949) This PR adds a new top-level flag `alwaysInsertFields` in the storage adapter plugin options to ensure the prefix field is always present in the schema. Some configurations have prefix dynamically set by environment, but this can cause schema/db drift and issues where db migrations are needed, as well as generated types being different between environments. Now you can add `alwaysInsertFields: true` at the plugin level so that the prefix field is always present regardless of what you set in `prefix`, even when the plugin is disabled: ``` s3Storage({ alwaysInsertFields: true, // prefix field will always exist in schema collections: { 'media': true, 'media-with-prefix': { prefix: process.env.MEDIA_PREFIX, // can be undefined without causing schema drift }, }, enabled: process.env.USE_S3 === 'true', // works even when disabled // ... }) ``` This is particularly useful for: - Multi-tenant setups where prefix is set dynamically - Environments where cloud storage is conditionally enabled (e.g., local dev vs production) - Ensuring consistent database schema across all environments **This will be enabled by default and removed as a flag in Payload v4.** --- .gitignore | 2 + docs/upload/storage-adapters.mdx | 11 +-- .../src/admin/fields/getFields.ts | 12 ++-- .../plugin-cloud-storage/src/admin/index.ts | 10 +-- .../src/fields/getFields.ts | 68 ++++++++++++------- packages/plugin-cloud-storage/src/plugin.ts | 39 ++++++++++- packages/plugin-cloud-storage/src/types.ts | 10 +++ packages/storage-azure/src/index.ts | 12 ++++ packages/storage-gcs/src/index.ts | 12 ++++ packages/storage-r2/src/index.ts | 12 ++++ packages/storage-s3/src/index.ts | 36 +++++++++- packages/storage-uploadthing/src/index.ts | 12 ++++ packages/storage-vercel-blob/src/index.ts | 12 ++++ .../MediaWithAlwaysInsertFields.ts | 15 ++++ test/storage-s3/config.ts | 29 +++++++- test/storage-s3/int.spec.ts | 21 ++++++ test/storage-s3/payload-types.ts | 45 ++++++++++++ test/storage-s3/shared.ts | 1 + 18 files changed, 315 insertions(+), 44 deletions(-) create mode 100644 test/storage-s3/collections/MediaWithAlwaysInsertFields.ts diff --git a/.gitignore b/.gitignore index 58c18bdecdb..1b788a54a10 100644 --- a/.gitignore +++ b/.gitignore @@ -344,6 +344,8 @@ test/google-cloud-storage test/azurestoragedata/ /media-without-delete-access /media-documents +/media-with-always-insert-fields + licenses.csv diff --git a/docs/upload/storage-adapters.mdx b/docs/upload/storage-adapters.mdx index b7c93df881d..1a8716d678e 100644 --- a/docs/upload/storage-adapters.mdx +++ b/docs/upload/storage-adapters.mdx @@ -368,10 +368,11 @@ export default buildConfig({ This plugin is configurable to work across many different Payload collections. A `*` denotes that the property is required. -| Option | Type | Description | -| ---------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | -| `collections` \* | `Record` | Object with keys set to the slug of collections you want to enable the plugin for, and values set to collection-specific options. | -| `enabled` | `boolean` | To conditionally enable/disable plugin. Default: `true`. | +| Option | Type | Description | +| -------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `alwaysInsertFields` | `boolean` | When enabled, fields (like the prefix field) will always be inserted into the collection schema regardless of whether the plugin is enabled. This will be enabled by default in Payload v4. Default: `false`. | +| `collections` \* | `Record` | Object with keys set to the slug of collections you want to enable the plugin for, and values set to collection-specific options. | +| `enabled` | `boolean` | To conditionally enable/disable plugin. Default: `true`. | ## Collection-specific options @@ -380,8 +381,8 @@ This plugin is configurable to work across many different Payload collections. A | `adapter` \* | [Adapter](https://github.com/payloadcms/payload/blob/main/packages/plugin-cloud-storage/src/types.ts#L49) | Pass in the adapter that you'd like to use for this collection. You can also set this field to `null` for local development if you'd like to bypass cloud storage in certain scenarios and use local storage. | | `disableLocalStorage` | `boolean` | Choose to disable local storage on this collection. Defaults to `true`. | | `disablePayloadAccessControl` | `true` | Set to `true` to disable Payload's Access Control. [More](#payload-access-control) | -| `prefix` | `string` | Set to `media/images` to upload files inside `media/images` folder in the bucket. | | `generateFileURL` | [GenerateFileURL](https://github.com/payloadcms/payload/blob/main/packages/plugin-cloud-storage/src/types.ts#L67) | Override the generated file URL with one that you create. | +| `prefix` | `string` | Set to `media/images` to upload files inside `media/images` folder in the bucket. | ## Payload Access Control diff --git a/packages/plugin-cloud-storage/src/admin/fields/getFields.ts b/packages/plugin-cloud-storage/src/admin/fields/getFields.ts index ea58964b5a6..9d188750949 100644 --- a/packages/plugin-cloud-storage/src/admin/fields/getFields.ts +++ b/packages/plugin-cloud-storage/src/admin/fields/getFields.ts @@ -3,11 +3,15 @@ import type { CollectionConfig, Field, GroupField, TextField } from 'payload' import path from 'path' interface Args { + /** + * When true, always insert the prefix field regardless of whether a prefix is configured. + */ + alwaysInsertFields?: boolean collection: CollectionConfig prefix?: string } -export const getFields = ({ collection, prefix }: Args): Field[] => { +export const getFields = ({ alwaysInsertFields, collection, prefix }: Args): Field[] => { const baseURLField: TextField = { name: 'url', type: 'text', @@ -99,8 +103,8 @@ export const getFields = ({ collection, prefix }: Args): Field[] => { fields.push(sizesField) } - // If prefix is enabled, save it to db - if (typeof prefix !== 'undefined') { + // If prefix is enabled or alwaysInsertFields is true, save it to db + if (typeof prefix !== 'undefined' || alwaysInsertFields) { let existingPrefixFieldIndex = -1 const existingPrefixField = fields.find((existingField, i) => { @@ -118,7 +122,7 @@ export const getFields = ({ collection, prefix }: Args): Field[] => { fields.push({ ...basePrefixField, ...(existingPrefixField || {}), - defaultValue: path.posix.join(prefix), + defaultValue: prefix ? path.posix.join(prefix) : '', } as TextField) } diff --git a/packages/plugin-cloud-storage/src/admin/index.ts b/packages/plugin-cloud-storage/src/admin/index.ts index 918490c6374..58572966001 100644 --- a/packages/plugin-cloud-storage/src/admin/index.ts +++ b/packages/plugin-cloud-storage/src/admin/index.ts @@ -10,11 +10,11 @@ import { getFields } from './fields/getFields.js' export const cloudStorage = (pluginOptions: PluginOptions) => (incomingConfig: Config): Config => { - const { collections: allCollectionOptions, enabled } = pluginOptions + const { alwaysInsertFields, collections: allCollectionOptions, enabled } = pluginOptions const config = { ...incomingConfig } - // Return early if disabled. Only webpack config mods are applied. - if (enabled === false) { + // If disabled and alwaysInsertFields is not true, skip processing + if (enabled === false && !alwaysInsertFields) { return config } @@ -23,8 +23,10 @@ export const cloudStorage = collections: (config.collections || []).map((existingCollection) => { const options = allCollectionOptions[existingCollection.slug] - if (options?.adapter) { + // Process if adapter exists OR if alwaysInsertFields is true and this collection is configured + if (options?.adapter || (alwaysInsertFields && options)) { const fields = getFields({ + alwaysInsertFields, collection: existingCollection, prefix: options.prefix, }) diff --git a/packages/plugin-cloud-storage/src/fields/getFields.ts b/packages/plugin-cloud-storage/src/fields/getFields.ts index 8ca75323c11..9b2f5066de7 100644 --- a/packages/plugin-cloud-storage/src/fields/getFields.ts +++ b/packages/plugin-cloud-storage/src/fields/getFields.ts @@ -7,7 +7,11 @@ import type { GeneratedAdapter, GenerateFileURL } from '../types.js' import { getAfterReadHook } from '../hooks/afterRead.js' interface Args { - adapter: GeneratedAdapter + adapter?: GeneratedAdapter + /** + * When true, always insert the prefix field regardless of whether a prefix is configured. + */ + alwaysInsertFields?: boolean collection: CollectionConfig disablePayloadAccessControl?: true generateFileURL?: GenerateFileURL @@ -16,6 +20,7 @@ interface Args { export const getFields = ({ adapter, + alwaysInsertFields, collection, disablePayloadAccessControl, generateFileURL, @@ -40,7 +45,7 @@ export const getFields = ({ }, } - const fields = [...collection.fields, ...(adapter.fields || [])] + const fields = [...collection.fields, ...(adapter?.fields || [])] // Inject a hook into all URL fields to generate URLs @@ -58,16 +63,24 @@ export const getFields = ({ fields.splice(existingURLFieldIndex, 1) } - fields.push({ - ...baseURLField, - ...(existingURLField || {}), - hooks: { - afterRead: [ - getAfterReadHook({ adapter, collection, disablePayloadAccessControl, generateFileURL }), - ...(existingURLField?.hooks?.afterRead || []), - ], - }, - } as TextField) + // Only add afterRead hook if adapter is provided + if (adapter) { + fields.push({ + ...baseURLField, + ...(existingURLField || {}), + hooks: { + afterRead: [ + getAfterReadHook({ adapter, collection, disablePayloadAccessControl, generateFileURL }), + ...(existingURLField?.hooks?.afterRead || []), + ], + }, + } as TextField) + } else { + fields.push({ + ...baseURLField, + ...(existingURLField || {}), + } as TextField) + } if (typeof collection.upload === 'object' && collection.upload.imageSizes) { let existingSizesFieldIndex = -1 @@ -99,15 +112,11 @@ export const getFields = ({ const existingSizeURLField = existingSizeField?.fields.find( (existingField) => 'name' in existingField && existingField.name === 'url', - ) as GroupField + ) as TextField - return { - ...existingSizeField, - name: size.name, - type: 'group', - fields: [ - ...(adapter.fields || []), - { + // Only add afterRead hook if adapter is provided + const sizeURLField: TextField = adapter + ? ({ ...(existingSizeURLField || {}), ...baseURLField, hooks: { @@ -125,8 +134,17 @@ export const getFields = ({ []), ], }, - }, - ], + } as TextField) + : ({ + ...(existingSizeURLField || {}), + ...baseURLField, + } as TextField) + + return { + ...existingSizeField, + name: size.name, + type: 'group', + fields: [...(adapter?.fields || []), sizeURLField], } as Field }), } @@ -134,8 +152,8 @@ export const getFields = ({ fields.push(sizesField) } - // If prefix is enabled, save it to db - if (typeof prefix !== 'undefined') { + // If prefix is enabled or alwaysInsertFields is true, save it to db + if (typeof prefix !== 'undefined' || alwaysInsertFields) { let existingPrefixFieldIndex = -1 const existingPrefixField = fields.find((existingField, i) => { @@ -153,7 +171,7 @@ export const getFields = ({ fields.push({ ...basePrefixField, ...(existingPrefixField || {}), - defaultValue: path.posix.join(prefix), + defaultValue: prefix ? path.posix.join(prefix) : '', } as TextField) } diff --git a/packages/plugin-cloud-storage/src/plugin.ts b/packages/plugin-cloud-storage/src/plugin.ts index 4f25c7fda1b..a4226a37099 100644 --- a/packages/plugin-cloud-storage/src/plugin.ts +++ b/packages/plugin-cloud-storage/src/plugin.ts @@ -18,11 +18,46 @@ import { getAfterDeleteHook } from './hooks/afterDelete.js' export const cloudStoragePlugin = (pluginOptions: PluginOptions) => (incomingConfig: Config): Config => { - const { collections: allCollectionOptions, enabled } = pluginOptions + const { alwaysInsertFields, collections: allCollectionOptions, enabled } = pluginOptions const config = { ...incomingConfig } - // Return early if disabled. Only webpack config mods are applied. + // If disabled but alwaysInsertFields is true, only insert fields without full plugin functionality if (enabled === false) { + if (alwaysInsertFields) { + return { + ...config, + collections: (config.collections || []).map((existingCollection) => { + const options = allCollectionOptions[existingCollection.slug] + + if (options) { + // If adapter is provided, use it to get fields + const adapter = options.adapter + ? options.adapter({ + collection: existingCollection, + prefix: options.prefix, + }) + : undefined + + const fields = getFields({ + adapter, + alwaysInsertFields: true, + collection: existingCollection, + disablePayloadAccessControl: options.disablePayloadAccessControl, + generateFileURL: options.generateFileURL, + prefix: options.prefix, + }) + + return { + ...existingCollection, + fields, + } + } + + return existingCollection + }), + } + } + return config } diff --git a/packages/plugin-cloud-storage/src/types.ts b/packages/plugin-cloud-storage/src/types.ts index 8b882311301..d3eef65fbcc 100644 --- a/packages/plugin-cloud-storage/src/types.ts +++ b/packages/plugin-cloud-storage/src/types.ts @@ -106,6 +106,16 @@ export interface CollectionOptions { } export interface PluginOptions { + /** + * When enabled, fields (like the prefix field) will always be inserted into + * the collection schema regardless of whether the plugin is enabled. This + * ensures a consistent schema across all environments. + * + * This will be enabled by default in Payload v4. + * + * @default false + */ + alwaysInsertFields?: boolean collections: Partial> /** * Whether or not to enable the plugin diff --git a/packages/storage-azure/src/index.ts b/packages/storage-azure/src/index.ts index c74b835c080..e52c6131b87 100644 --- a/packages/storage-azure/src/index.ts +++ b/packages/storage-azure/src/index.ts @@ -26,6 +26,17 @@ export type AzureStorageOptions = { */ allowContainerCreate: boolean + /** + * When enabled, fields (like the prefix field) will always be inserted into + * the collection schema regardless of whether the plugin is enabled. This + * ensures a consistent schema across all environments. + * + * This will be enabled by default in Payload v4. + * + * @default false + */ + alwaysInsertFields?: boolean + /** * Base URL for the Azure Blob storage account */ @@ -136,6 +147,7 @@ export const azureStorage: AzureStoragePlugin = } return cloudStoragePlugin({ + alwaysInsertFields: azureStorageOptions.alwaysInsertFields, collections: collectionsWithAdapter, })(config) } diff --git a/packages/storage-gcs/src/index.ts b/packages/storage-gcs/src/index.ts index 75e2b725e31..6c14c0e46a6 100644 --- a/packages/storage-gcs/src/index.ts +++ b/packages/storage-gcs/src/index.ts @@ -21,6 +21,17 @@ import { getHandler } from './staticHandler.js' export interface GcsStorageOptions { acl?: 'Private' | 'Public' + /** + * When enabled, fields (like the prefix field) will always be inserted into + * the collection schema regardless of whether the plugin is enabled. This + * ensures a consistent schema across all environments. + * + * This will be enabled by default in Payload v4. + * + * @default false + */ + alwaysInsertFields?: boolean + /** * The name of the bucket to use. */ @@ -131,6 +142,7 @@ export const gcsStorage: GcsStoragePlugin = } return cloudStoragePlugin({ + alwaysInsertFields: gcsStorageOptions.alwaysInsertFields, collections: collectionsWithAdapter, })(config) } diff --git a/packages/storage-r2/src/index.ts b/packages/storage-r2/src/index.ts index 7a22a4c7885..fa24659ec12 100644 --- a/packages/storage-r2/src/index.ts +++ b/packages/storage-r2/src/index.ts @@ -15,6 +15,17 @@ import { getHandleUpload } from './handleUpload.js' import { getHandler } from './staticHandler.js' export interface R2StorageOptions { + /** + * When enabled, fields (like the prefix field) will always be inserted into + * the collection schema regardless of whether the plugin is enabled. This + * ensures a consistent schema across all environments. + * + * This will be enabled by default in Payload v4. + * + * @default false + */ + alwaysInsertFields?: boolean + bucket: R2Bucket /** * Collection options to apply the R2 adapter to. @@ -69,6 +80,7 @@ export const r2Storage: R2StoragePlugin = } return cloudStoragePlugin({ + alwaysInsertFields: r2StorageOptions.alwaysInsertFields, collections: collectionsWithAdapter, })(config) } diff --git a/packages/storage-s3/src/index.ts b/packages/storage-s3/src/index.ts index 3bc8723f498..5efc23dbcba 100644 --- a/packages/storage-s3/src/index.ts +++ b/packages/storage-s3/src/index.ts @@ -24,9 +24,19 @@ export type S3StorageOptions = { /** * Access control list for uploaded files. */ - acl?: 'private' | 'public-read' + /** + * When enabled, fields (like the prefix field) will always be inserted into + * the collection schema regardless of whether the plugin is enabled. This + * ensures a consistent schema across all environments. + * + * This will be enabled by default in Payload v4. + * + * @default false + */ + alwaysInsertFields?: boolean + /** * Bucket name to upload files to. * @@ -142,6 +152,29 @@ export const s3Storage: S3StoragePlugin = }) if (isPluginDisabled) { + // If alwaysInsertFields is true, still call cloudStoragePlugin to insert fields + if (s3StorageOptions.alwaysInsertFields) { + // Build collections with adapter: null since plugin is disabled + const collectionsWithoutAdapter: CloudStoragePluginOptions['collections'] = Object.entries( + s3StorageOptions.collections, + ).reduce( + (acc, [slug, collOptions]) => ({ + ...acc, + [slug]: { + ...(collOptions === true ? {} : collOptions), + adapter: null, + }, + }), + {} as Record, + ) + + return cloudStoragePlugin({ + alwaysInsertFields: true, + collections: collectionsWithoutAdapter, + enabled: false, + })(incomingConfig) + } + return incomingConfig } @@ -180,6 +213,7 @@ export const s3Storage: S3StoragePlugin = } return cloudStoragePlugin({ + alwaysInsertFields: s3StorageOptions.alwaysInsertFields, collections: collectionsWithAdapter, })(config) } diff --git a/packages/storage-uploadthing/src/index.ts b/packages/storage-uploadthing/src/index.ts index 01ca956306f..85476ef1598 100644 --- a/packages/storage-uploadthing/src/index.ts +++ b/packages/storage-uploadthing/src/index.ts @@ -22,6 +22,17 @@ import { getHandler } from './staticHandler.js' export type FileRouterInputConfig = Parameters>[0] export type UploadthingStorageOptions = { + /** + * When enabled, fields (like the prefix field) will always be inserted into + * the collection schema regardless of whether the plugin is enabled. This + * ensures a consistent schema across all environments. + * + * This will be enabled by default in Payload v4. + * + * @default false + */ + alwaysInsertFields?: boolean + /** * Do uploads directly on the client, to bypass limits on Vercel. */ @@ -135,6 +146,7 @@ export const uploadthingStorage: UploadthingPlugin = } return cloudStoragePlugin({ + alwaysInsertFields: uploadthingStorageOptions.alwaysInsertFields, collections: collectionsWithAdapter, })(config) } diff --git a/packages/storage-vercel-blob/src/index.ts b/packages/storage-vercel-blob/src/index.ts index dccdd6fb91a..65f83d8fd4d 100644 --- a/packages/storage-vercel-blob/src/index.ts +++ b/packages/storage-vercel-blob/src/index.ts @@ -34,6 +34,17 @@ export type VercelBlobStorageOptions = { */ addRandomSuffix?: boolean + /** + * When enabled, fields (like the prefix field) will always be inserted into + * the collection schema regardless of whether the plugin is enabled. This + * ensures a consistent schema across all environments. + * + * This will be enabled by default in Payload v4. + * + * @default false + */ + alwaysInsertFields?: boolean + /** * Cache-Control max-age in seconds * @@ -165,6 +176,7 @@ export const vercelBlobStorage: VercelBlobStoragePlugin = } return cloudStoragePlugin({ + alwaysInsertFields: options.alwaysInsertFields, collections: collectionsWithAdapter, })(config) } diff --git a/test/storage-s3/collections/MediaWithAlwaysInsertFields.ts b/test/storage-s3/collections/MediaWithAlwaysInsertFields.ts new file mode 100644 index 00000000000..c2e6203be9d --- /dev/null +++ b/test/storage-s3/collections/MediaWithAlwaysInsertFields.ts @@ -0,0 +1,15 @@ +import type { CollectionConfig } from 'payload' + +import { mediaWithAlwaysInsertFieldsSlug } from '../shared.js' + +export const MediaWithAlwaysInsertFields: CollectionConfig = { + slug: mediaWithAlwaysInsertFieldsSlug, + upload: true, + fields: [ + { + name: 'alt', + label: 'Alt Text', + type: 'text', + }, + ], +} diff --git a/test/storage-s3/config.ts b/test/storage-s3/config.ts index 941a39b8be8..02857ec93c0 100644 --- a/test/storage-s3/config.ts +++ b/test/storage-s3/config.ts @@ -6,6 +6,7 @@ import path from 'path' import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { devUser } from '../credentials.js' import { Media } from './collections/Media.js' +import { MediaWithAlwaysInsertFields } from './collections/MediaWithAlwaysInsertFields.js' import { MediaWithDirectAccess } from './collections/MediaWithDirectAccess.js' import { MediaWithDynamicPrefix } from './collections/MediaWithDynamicPrefix.js' import { MediaWithPrefix } from './collections/MediaWithPrefix.js' @@ -13,6 +14,7 @@ import { MediaWithSignedDownloads } from './collections/MediaWithSignedDownloads import { Users } from './collections/Users.js' import { mediaSlug, + mediaWithAlwaysInsertFieldsSlug, mediaWithDirectAccessSlug, mediaWithDynamicPrefixSlug, mediaWithPrefixSlug, @@ -37,6 +39,7 @@ export default buildConfigWithDefaults({ }, collections: [ Media, + MediaWithAlwaysInsertFields, MediaWithDirectAccess, MediaWithDynamicPrefix, MediaWithPrefix, @@ -71,17 +74,37 @@ export default buildConfigWithDefaults({ }, }, }, - bucket: process.env.S3_BUCKET, + bucket: process.env.S3_BUCKET!, config: { credentials: { - accessKeyId: process.env.S3_ACCESS_KEY_ID, - secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + accessKeyId: process.env.S3_ACCESS_KEY_ID!, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!, }, endpoint: process.env.S3_ENDPOINT, forcePathStyle: process.env.S3_FORCE_PATH_STYLE === 'true', region: process.env.S3_REGION, }, }), + // Test alwaysInsertFields with enabled: false + s3Storage({ + alwaysInsertFields: true, + collections: { + [mediaWithAlwaysInsertFieldsSlug]: { + prefix: '', + }, + }, + bucket: process.env.S3_BUCKET!, + config: { + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID!, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!, + }, + endpoint: process.env.S3_ENDPOINT, + forcePathStyle: process.env.S3_FORCE_PATH_STYLE === 'true', + region: process.env.S3_REGION, + }, + enabled: false, + }), ], upload: uploadOptions, typescript: { diff --git a/test/storage-s3/int.spec.ts b/test/storage-s3/int.spec.ts index 7aaccf63830..d1cd15082d0 100644 --- a/test/storage-s3/int.spec.ts +++ b/test/storage-s3/int.spec.ts @@ -10,6 +10,7 @@ import type { NextRESTClient } from '../helpers/NextRESTClient.js' import { initPayloadInt } from '../helpers/initPayloadInt.js' import { mediaSlug, + mediaWithAlwaysInsertFieldsSlug, mediaWithDirectAccessSlug, mediaWithDynamicPrefixSlug, mediaWithPrefixSlug, @@ -87,6 +88,22 @@ describe('@payloadcms/storage-s3', () => { expect(upload.url).toEqual(`/api/${mediaWithPrefixSlug}/file/${String(upload.filename)}`) }) + it('has prefix field with alwaysInsertFields even when plugin is disabled', async () => { + // This collection uses a s3Storage plugin with enabled: false but alwaysInsertFields: true + // The upload will use local storage, but the prefix field should still exist + const upload = await payload.create({ + collection: mediaWithAlwaysInsertFieldsSlug, + data: { + prefix: 'test', + }, + filePath: path.resolve(dirname, '../uploads/image.png'), + }) + + expect(upload.id).toBeTruthy() + // With alwaysInsertFields: true and enabled: false, the prefix field should still exist + expect(upload.prefix).toBe('test') + }) + it('can download with signed downloads', async () => { await payload.create({ collection: mediaWithSignedDownloadsSlug, @@ -183,6 +200,10 @@ describe('@payloadcms/storage-s3', () => { collection: mediaSlug, where: {}, }) + await payload.delete({ + collection: mediaWithAlwaysInsertFieldsSlug, + where: {}, + }) }) it('detects collision within same prefix', async () => { diff --git a/test/storage-s3/payload-types.ts b/test/storage-s3/payload-types.ts index 72400185656..eaa45096443 100644 --- a/test/storage-s3/payload-types.ts +++ b/test/storage-s3/payload-types.ts @@ -68,6 +68,7 @@ export interface Config { blocks: {}; collections: { media: Media; + 'media-with-always-insert-fields': MediaWithAlwaysInsertField; 'media-with-direct-access': MediaWithDirectAccess; 'media-with-dynamic-prefix': MediaWithDynamicPrefix; 'media-with-prefix': MediaWithPrefix; @@ -81,6 +82,7 @@ export interface Config { collectionsJoins: {}; collectionsSelect: { media: MediaSelect | MediaSelect; + 'media-with-always-insert-fields': MediaWithAlwaysInsertFieldsSelect | MediaWithAlwaysInsertFieldsSelect; 'media-with-direct-access': MediaWithDirectAccessSelect | MediaWithDirectAccessSelect; 'media-with-dynamic-prefix': MediaWithDynamicPrefixSelect | MediaWithDynamicPrefixSelect; 'media-with-prefix': MediaWithPrefixSelect | MediaWithPrefixSelect; @@ -161,6 +163,26 @@ export interface Media { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "media-with-always-insert-fields". + */ +export interface MediaWithAlwaysInsertField { + id: string; + alt?: string | null; + prefix?: string | null; + updatedAt: string; + createdAt: string; + url?: string | null; + thumbnailURL?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + focalX?: number | null; + focalY?: number | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "media-with-direct-access". @@ -289,6 +311,10 @@ export interface PayloadLockedDocument { relationTo: 'media'; value: string | Media; } | null) + | ({ + relationTo: 'media-with-always-insert-fields'; + value: string | MediaWithAlwaysInsertField; + } | null) | ({ relationTo: 'media-with-direct-access'; value: string | MediaWithDirectAccess; @@ -393,6 +419,25 @@ export interface MediaSelect { }; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "media-with-always-insert-fields_select". + */ +export interface MediaWithAlwaysInsertFieldsSelect { + alt?: T; + prefix?: T; + updatedAt?: T; + createdAt?: T; + url?: T; + thumbnailURL?: T; + filename?: T; + mimeType?: T; + filesize?: T; + width?: T; + height?: T; + focalX?: T; + focalY?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "media-with-direct-access_select". diff --git a/test/storage-s3/shared.ts b/test/storage-s3/shared.ts index ee95c9b596d..9df7f68c228 100644 --- a/test/storage-s3/shared.ts +++ b/test/storage-s3/shared.ts @@ -1,6 +1,7 @@ export const mediaSlug = 'media' export const mediaWithPrefixSlug = 'media-with-prefix' export const mediaWithDynamicPrefixSlug = 'media-with-dynamic-prefix' +export const mediaWithAlwaysInsertFieldsSlug = 'media-with-always-insert-fields' export const prefix = 'test-prefix' export const mediaWithSignedDownloadsSlug = 'media-with-signed-downloads' From 6632e65fe16eaab03d8204e025bde626fe7b14bb Mon Sep 17 00:00:00 2001 From: Vincent Vu <172068404+rubixvi@users.noreply.github.com> Date: Tue, 6 Jan 2026 05:23:32 +1100 Subject: [PATCH 50/67] fix(ui): invalid sass imports to support windows - add Stylelint to prevent regression (#15028) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes invalid Sass import paths in the compiled @payloadcms/ui output that currently rely on legacy webpack resolution behavior. Fixes issue #15011 ``` ./nodemodules/.pnpm/@payloadcms+ui@3.69.0@type_f6dae4b1d169b9370a166162f9bf6e5f/node_modules/@payloadcms/ui/dist/widgets/CollectionCards/index.scss Error evaluating Node.js code Error: Can't find stylesheet to import. ╷ 1 │ @import 'vars'; │ ^^^^^^ ``` Patch file ``` diff --git a/dist/widgets/CollectionCards/index.scss b/dist/widgets/CollectionCards/index.scss index 0330e9c283160e35ad22f7f244bba840bc57c66f..c8776a72ede7877fc2fba855a89b96603f7eb5b9 100644 --- a/dist/widgets/CollectionCards/index.scss +++ b/dist/widgets/CollectionCards/index.scss @@ -1,4 +1,4 @@ -@import '~@payloadcms/ui/scss'; +@import '../../scss/styles'; @layer payload-default { .collections { ``` Running a patch file to adjust this import fixes the issue. --------- Co-authored-by: German Jablonski <43938777+GermanJablo@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/main.yml | 5 +- .stylelint/no-tilde-imports.js | 51 ++ .stylelintrc.json | 7 + .vscode/extensions.json | 1 + .vscode/settings.json | 7 +- package.json | 4 + .../ui/src/providers/LivePreview/index.scss | 2 +- .../ui/src/widgets/CollectionCards/index.scss | 2 +- pnpm-lock.yaml | 521 +++++++++++++++--- 9 files changed, 514 insertions(+), 86 deletions(-) create mode 100644 .stylelint/no-tilde-imports.js create mode 100644 .stylelintrc.json diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b334daa8326..392e03d9d5f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -66,9 +66,12 @@ jobs: - name: Node setup uses: ./.github/actions/setup - - name: Lint + - name: Lint TypeScript/JavaScript run: pnpm lint -- --quiet + - name: Lint SCSS + run: pnpm run lint:scss + build: needs: changes if: needs.changes.outputs.needs_build == 'true' diff --git a/.stylelint/no-tilde-imports.js b/.stylelint/no-tilde-imports.js new file mode 100644 index 00000000000..b0cb749c31a --- /dev/null +++ b/.stylelint/no-tilde-imports.js @@ -0,0 +1,51 @@ +import stylelint from 'stylelint' + +const ruleName = 'plugin/no-tilde-imports' +const messages = stylelint.utils.ruleMessages(ruleName, { + rejected: (importPath) => + `Unexpected tilde (~) in import "${importPath}". Use relative paths instead. See PR #15028`, +}) + +const ruleFunction = (enabled) => { + return (root, result) => { + const validOptions = stylelint.utils.validateOptions(result, ruleName, { + actual: enabled, + possible: [true, false], + }) + + if (!validOptions || !enabled) { + return + } + + root.walkAtRules('import', (atRule) => { + const importValue = atRule.params.replace(/['"`]/g, '').trim() + + if (importValue.startsWith('~')) { + stylelint.utils.report({ + message: messages.rejected(atRule.params), + node: atRule, + result, + ruleName, + }) + } + }) + + root.walkAtRules('use', (atRule) => { + const importValue = atRule.params.replace(/['"`]/g, '').trim() + + if (importValue.startsWith('~')) { + stylelint.utils.report({ + message: messages.rejected(atRule.params), + node: atRule, + result, + ruleName, + }) + } + }) + } +} + +ruleFunction.ruleName = ruleName +ruleFunction.messages = messages + +export default stylelint.createPlugin(ruleName, ruleFunction) diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 00000000000..4dc41893d09 --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,7 @@ +{ + "customSyntax": "postcss-scss", + "plugins": ["./.stylelint/no-tilde-imports.js"], + "rules": { + "plugin/no-tilde-imports": true + } +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index a46d5032898..2b2d0d78e9e 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,6 +2,7 @@ "recommendations": [ "esbenp.prettier-vscode", "dbaeumer.vscode-eslint", + "stylelint.vscode-stylelint", "vitest.explorer", "ms-playwright.playwright" ] diff --git a/.vscode/settings.json b/.vscode/settings.json index 8317ba4ac97..f3db5f10463 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,8 @@ "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" + "source.fixAll.eslint": "explicit", + "source.fixAll.stylelint": "explicit" }, "editor.formatOnSaveMode": "file", "files.insertFinalNewline": true, @@ -14,6 +15,10 @@ { "rule": "curly", "severity": "off", "fixable": true }, { "rule": "object-shorthand", "severity": "off", "fixable": true } ], + "stylelint.enable": true, + "stylelint.validate": ["css", "scss"], + "css.validate": false, + "scss.validate": false, "typescript.tsdk": "node_modules/typescript/lib", // Load .git-blame-ignore-revs file "gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"], diff --git a/package.json b/package.json index 96b1d29b63e..27e54f9cacb 100644 --- a/package.json +++ b/package.json @@ -103,6 +103,7 @@ "lint": "turbo run lint --log-order=grouped --continue --filter \"!blank\" --filter \"!website\" --filter \"!ecommerce\"", "lint-staged": "lint-staged", "lint:fix": "turbo run lint:fix --log-order=grouped --continue --filter \"!blank\" --filter \"!website\" --filter \"!ecommerce\"", + "lint:scss": "stylelint \"packages/ui/src/**/*.scss\"", "obliterate-playwright-cache-macos": "rm -rf ~/Library/Caches/ms-playwright && find /System/Volumes/Data/private/var/folders -type d -name 'playwright*' -exec rm -rf {} +", "prepare": "husky", "prepare-run-test-against-prod": "pnpm bf && rm -rf test/packed && rm -rf test/node_modules && rm -rf app && rm -f test/pnpm-lock.yaml && pnpm run script:pack --all --no-build --dest test/packed && pnpm runts test/setupProd.ts && cd test && pnpm i --ignore-workspace && cd ..", @@ -193,6 +194,8 @@ "pg": "8.16.3", "playwright": "1.56.1", "playwright-core": "1.56.1", + "postcss": "^8.4.49", + "postcss-scss": "^4.0.9", "prettier": "3.5.3", "react": "19.2.1", "react-dom": "19.2.1", @@ -201,6 +204,7 @@ "shelljs": "0.8.5", "slash": "3.0.0", "sort-package-json": "^2.10.0", + "stylelint": "^16.12.0", "swc-plugin-transform-remove-imports": "8.3.0", "tempy": "1.0.1", "tstyche": "3.5.0", diff --git a/packages/ui/src/providers/LivePreview/index.scss b/packages/ui/src/providers/LivePreview/index.scss index 69dd322d40d..d0aeca5569c 100644 --- a/packages/ui/src/providers/LivePreview/index.scss +++ b/packages/ui/src/providers/LivePreview/index.scss @@ -1,4 +1,4 @@ -@import '~@payloadcms/ui/scss'; +@import '../../scss/styles'; @layer payload-default { .live-preview { diff --git a/packages/ui/src/widgets/CollectionCards/index.scss b/packages/ui/src/widgets/CollectionCards/index.scss index 0330e9c2831..c8776a72ede 100644 --- a/packages/ui/src/widgets/CollectionCards/index.scss +++ b/packages/ui/src/widgets/CollectionCards/index.scss @@ -1,4 +1,4 @@ -@import '~@payloadcms/ui/scss'; +@import '../../scss/styles'; @layer payload-default { .collections { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddb9c3fe35b..5c15ce34dde 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,6 +146,12 @@ importers: playwright-core: specifier: 1.56.1 version: 1.56.1 + postcss: + specifier: ^8.4.49 + version: 8.5.6 + postcss-scss: + specifier: ^4.0.9 + version: 4.0.9(postcss@8.5.6) prettier: specifier: 3.5.3 version: 3.5.3 @@ -170,6 +176,9 @@ importers: sort-package-json: specifier: ^2.10.0 version: 2.10.1 + stylelint: + specifier: ^16.12.0 + version: 16.26.1(typescript@5.7.3) swc-plugin-transform-remove-imports: specifier: 8.3.0 version: 8.3.0 @@ -2448,7 +2457,7 @@ importers: version: link:../packages/ui '@sentry/nextjs': specifier: ^8.33.1 - version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) + version: 8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3)) '@sentry/react': specifier: ^7.77.0 version: 7.119.2(react@19.2.1) @@ -3885,6 +3894,12 @@ packages: '@bufbuild/protobuf@2.2.2': resolution: {integrity: sha512-UNtPCbrwrenpmrXuRwn9jYpPoweNXj8X5sMvYgsqYyaH8jQ6LfUJSk3dJLnBK+6sfYPrF4iAIo5sd5HQ+tg75A==} + '@cacheable/memory@2.0.7': + resolution: {integrity: sha512-RbxnxAMf89Tp1dLhXMS7ceft/PGsDl1Ip7T20z5nZ+pwIAsQ1p2izPjVG69oCLv/jfQ7HDPHTWK0c9rcAWXN3A==} + + '@cacheable/utils@2.3.3': + resolution: {integrity: sha512-JsXDL70gQ+1Vc2W/KUFfkAJzgb4puKwwKehNLuB+HrNKWf91O736kGfxn4KujXCCSuh6mRRL4XEB0PkAFjWS0A==} + '@clack/core@0.3.4': resolution: {integrity: sha512-H4hxZDXgHtWTwV3RAVenqcC4VbJZNegbBjlPvzOzCouXtS2y3sDvlO3IsbrPNWuLWPPlYVYPghQdSF64683Ldw==} @@ -3967,10 +3982,27 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-syntax-patches-for-csstree@1.0.22': + resolution: {integrity: sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==} + engines: {node: '>=18'} + '@csstools/css-tokenizer@3.0.4': resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} + '@csstools/media-query-list-parser@4.0.3': + resolution: {integrity: sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/selector-specificity@5.0.0': + resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} + engines: {node: '>=18'} + peerDependencies: + postcss-selector-parser: ^7.0.0 + '@date-fns/tz@1.2.0': resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==} @@ -4013,6 +4045,9 @@ packages: '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@dual-bundle/import-meta-resolve@4.2.1': + resolution: {integrity: sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==} + '@ecies/ciphers@0.2.4': resolution: {integrity: sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==} engines: {bun: '>=1', deno: '>=2', node: '>=16'} @@ -5248,6 +5283,15 @@ packages: '@juggle/resize-observer@3.4.0': resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} + '@keyv/bigmap@1.3.0': + resolution: {integrity: sha512-KT01GjzV6AQD5+IYrcpoYLkCu1Jod3nau1Z7EsEuViO3TZGRacSbO9MfHmbJ1WaOXFtWLxPVj169cn2WNKPkIg==} + engines: {node: '>= 18'} + peerDependencies: + keyv: ^5.5.4 + + '@keyv/serialize@1.1.1': + resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + '@lexical/clipboard@0.35.0': resolution: {integrity: sha512-ko7xSIIiayvDiqjNDX6fgH9RlcM6r9vrrvJYTcfGVBor5httx16lhIi0QJZ4+RNPvGtTjyFv4bwRmsixRRwImg==} @@ -8571,6 +8615,10 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} @@ -8651,6 +8699,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@2.0.0: + resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} + bare-events@2.5.0: resolution: {integrity: sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==} @@ -8814,6 +8865,9 @@ packages: resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} engines: {node: '>=14.16'} + cacheable@2.3.1: + resolution: {integrity: sha512-yr+FSHWn1ZUou5LkULX/S+jhfgfnLbuKQjE40tyEd4fxGZVMbBL5ifno0J0OauykS8UiCSgHi+DV/YD+rjFxFg==} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -8983,6 +9037,9 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -9101,6 +9158,15 @@ packages: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: 5.7.3 + peerDependenciesMeta: + typescript: + optional: true + croner@9.1.0: resolution: {integrity: sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==} engines: {node: '>=18.0'} @@ -9125,6 +9191,14 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} + css-functions-list@3.2.3: + resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==} + engines: {node: '>=12 || >=16'} + + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -9617,6 +9691,10 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + env-paths@3.0.0: resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -10122,6 +10200,10 @@ packages: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -10150,6 +10232,10 @@ packages: resolution: {integrity: sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==} hasBin: true + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -10186,6 +10272,9 @@ packages: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} + file-entry-cache@11.1.1: + resolution: {integrity: sha512-TPVFSDE7q91Dlk1xpFLvFllf8r0HyOMOlnWy7Z2HBku5H3KhIeOGInexrIeg2D64DosVB/JXkrrk6N/7Wriq4A==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -10246,9 +10335,15 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} + flat-cache@6.1.19: + resolution: {integrity: sha512-l/K33newPTZMTGAnnzaiqSl6NnH7Namh8jBNjrgjprWxGmZUuxx/sJNIRaijOh3n7q7ESbhNZC+pvVZMFdeU4A==} + flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + focus-trap@7.5.4: resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==} @@ -10473,10 +10568,18 @@ packages: resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} engines: {node: '>=0.10.0'} + global-modules@2.0.0: + resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} + engines: {node: '>=6'} + global-prefix@1.0.2: resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} engines: {node: '>=0.10.0'} + global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -10505,6 +10608,9 @@ packages: resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + globjoin@0.1.4: + resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} + globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -10594,6 +10700,10 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + hashery@1.4.0: + resolution: {integrity: sha512-Wn2i1In6XFxl8Az55kkgnFRiAlIAushzh26PTjL2AKtQcEfXrcLa7Hn5QOWGZEf3LU057P9TwwZjFyxfS1VuvQ==} + engines: {node: '>=20'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -10614,6 +10724,9 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} + hookified@1.15.0: + resolution: {integrity: sha512-51w+ZZGt7Zw5q7rM3nC4t3aLn/xvKDETsXqMczndvwyVQhAHfUmUuFBRFcos8Iyebtk7OAE9dL26wFNzZVVOkw==} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -10627,6 +10740,10 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} @@ -10697,6 +10814,10 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + image-size@2.0.2: resolution: {integrity: sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==} engines: {node: '>=16.x'} @@ -11187,6 +11308,9 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@5.5.5: + resolution: {integrity: sha512-FA5LmZVF1VziNc0bIdCSA1IoSVnDCqE8HJIZZv2/W8YmoAM50+tnUgJR/gQZwEeIMleuIOnRnHA/UaZRNeV4iQ==} + kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -11199,6 +11323,9 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} + known-css-properties@0.37.0: + resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==} + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -11353,6 +11480,9 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -11427,6 +11557,9 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mathml-tag-names@2.1.3: + resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} + mcp-handler@1.0.4: resolution: {integrity: sha512-bp5Xp6jKF8H3vh3Xadr83YZxHekKCXcbenTIej3DR0MK8GpQDMHNU/RDBvIRbs/7VRViPPkjMcWLsx+WYVICNw==} hasBin: true @@ -11455,6 +11588,9 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + media-typer@1.1.0: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} @@ -11465,6 +11601,10 @@ packages: memory-pager@1.5.0: resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + meow@13.2.0: + resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} + engines: {node: '>=18'} + merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} @@ -11818,6 +11958,7 @@ packages: next@15.5.4: resolution: {integrity: sha512-xH4Yjhb82sFYQfY3vbkJfgSDgXvBB6a8xPs9i35k6oZJRoQRihZH+4s9Yo2qsWpzBmZ3lPXaJ2KPXLfkvW4LnA==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -12329,6 +12470,21 @@ packages: peerDependencies: postcss: ^8.2.14 + postcss-resolve-nested-selector@0.1.6: + resolution: {integrity: sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==} + + postcss-safe-parser@7.0.1: + resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.4.31 + + postcss-scss@4.0.9: + resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.4.29 + postcss-selector-parser@6.0.10: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} engines: {node: '>=4'} @@ -12337,6 +12493,10 @@ packages: resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} engines: {node: '>=4'} + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -12348,6 +12508,10 @@ packages: resolution: {integrity: sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} @@ -12508,6 +12672,10 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qified@0.5.3: + resolution: {integrity: sha512-kXuQdQTB6oN3KhI6V4acnBSZx8D2I4xzZvn9+wFLLFCoBNQY/sFnCW6c43OL7pOQ2HvGV4lnWIXNmgfp7cTWhQ==} + engines: {node: '>=20'} + qs-esm@7.0.2: resolution: {integrity: sha512-D8NAthKSD7SGn748v+GLaaO6k08Mvpoqroa35PqIQC4gtUa8/Pb/k+r0m0NnGBVbHDP1gKZ2nVywqfMisRhV5A==} engines: {node: '>=18'} @@ -12804,6 +12972,10 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -13268,6 +13440,10 @@ packages: slate@0.91.4: resolution: {integrity: sha512-aUJ3rpjrdi5SbJ5G1Qjr3arytfRkEStTmHjBfWq2A2Q8MybacIzkScSvGJjQkdTk3djCK9C9SEOt39sSeZFwTw==} + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} @@ -13570,6 +13746,11 @@ packages: babel-plugin-macros: optional: true + stylelint@16.26.1: + resolution: {integrity: sha512-v20V59/crfc8sVTAtge0mdafI3AdnzQ2KsWe6v523L4OA1bJO02S7MO2oyXDCS6iWb9ckIPnqAFVItqSBQr7jw==} + engines: {node: '>=18.12.0'} + hasBin: true + stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} @@ -13598,10 +13779,17 @@ packages: resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} engines: {node: '>=8'} + supports-hyperlinks@3.2.0: + resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} + engines: {node: '>=14.18'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svg-tags@1.0.0: + resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + swc-plugin-transform-remove-imports@8.3.0: resolution: {integrity: sha512-0sETKqTgQXeiAaRDjTYLyz8JcQoAPluzL8OLC8/xR1gPXLoAZ/DPdGwO9Sp5z1gqeOMgQLp/pouoxivvrWHqCA==} @@ -13611,6 +13799,10 @@ packages: tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + tailwind-merge@2.6.0: resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} @@ -14498,6 +14690,10 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@7.5.10: resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} engines: {node: '>=8.3.0'} @@ -17195,6 +17391,18 @@ snapshots: '@bufbuild/protobuf@2.2.2': {} + '@cacheable/memory@2.0.7': + dependencies: + '@cacheable/utils': 2.3.3 + '@keyv/bigmap': 1.3.0(keyv@5.5.5) + hookified: 1.15.0 + keyv: 5.5.5 + + '@cacheable/utils@2.3.3': + dependencies: + hashery: 1.4.0 + keyv: 5.5.5 + '@clack/core@0.3.4': dependencies: picocolors: 1.1.1 @@ -17255,8 +17463,19 @@ snapshots: dependencies: '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-syntax-patches-for-csstree@1.0.22': {} + '@csstools/css-tokenizer@3.0.4': {} + '@csstools/media-query-list-parser@4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.1)': + dependencies: + postcss-selector-parser: 7.1.1 + '@date-fns/tz@1.2.0': {} '@discoveryjs/json-ext@0.5.7': {} @@ -17307,6 +17526,8 @@ snapshots: '@drizzle-team/brocli@0.10.2': {} + '@dual-bundle/import-meta-resolve@4.2.1': {} + '@ecies/ciphers@0.2.4(@noble/ciphers@1.3.0)': dependencies: '@noble/ciphers': 1.3.0 @@ -18269,6 +18490,14 @@ snapshots: '@juggle/resize-observer@3.4.0': {} + '@keyv/bigmap@1.3.0(keyv@5.5.5)': + dependencies: + hashery: 1.4.0 + hookified: 1.15.0 + keyv: 5.5.5 + + '@keyv/serialize@1.1.1': {} + '@lexical/clipboard@0.35.0': dependencies: '@lexical/html': 0.35.0 @@ -19767,35 +19996,6 @@ snapshots: '@sentry/utils': 7.119.2 localforage: 1.10.0 - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.27.0 - '@rollup/plugin-commonjs': 26.0.1(rollup@3.29.5) - '@sentry-internal/browser-utils': 8.37.1 - '@sentry/core': 8.37.1 - '@sentry/node': 8.37.1 - '@sentry/opentelemetry': 8.37.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.27.0) - '@sentry/react': 8.37.1(react@19.2.1) - '@sentry/types': 8.37.1 - '@sentry/utils': 8.37.1 - '@sentry/vercel-edge': 8.37.1 - '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.15.3)) - chalk: 3.0.0 - next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) - resolve: 1.22.8 - rollup: 3.29.5 - stacktrace-parser: 0.1.10 - transitivePeerDependencies: - - '@opentelemetry/core' - - '@opentelemetry/instrumentation' - - '@opentelemetry/sdk-trace-base' - - encoding - - react - - supports-color - - webpack - '@sentry/nextjs@8.37.1(@opentelemetry/core@1.27.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4))(react@19.2.1)(webpack@5.96.1(@swc/core@1.15.3))': dependencies: '@opentelemetry/api': 1.9.0 @@ -19812,7 +20012,7 @@ snapshots: '@sentry/vercel-edge': 8.37.1 '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.15.3)) chalk: 3.0.0 - next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) resolve: 1.22.8 rollup: 3.29.5 stacktrace-parser: 0.1.10 @@ -21189,7 +21389,7 @@ snapshots: '@tailwindcss/node': 4.0.12 '@tailwindcss/oxide': 4.0.12 lightningcss: 1.30.1 - postcss: 8.5.5 + postcss: 8.5.6 tailwindcss: 4.0.12 '@tailwindcss/typography@0.5.16(tailwindcss@3.4.17)': @@ -21956,7 +22156,7 @@ snapshots: '@vue/shared': 3.5.12 estree-walker: 2.0.2 magic-string: 0.30.17 - postcss: 8.5.5 + postcss: 8.5.6 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.12': @@ -22371,6 +22571,8 @@ snapshots: ast-types-flow@0.0.8: {} + astral-regex@2.0.0: {} + async-function@1.0.0: {} async-mutex@0.5.0: @@ -22451,6 +22653,8 @@ snapshots: balanced-match@1.0.2: {} + balanced-match@2.0.0: {} + bare-events@2.5.0: optional: true @@ -22635,6 +22839,14 @@ snapshots: normalize-url: 8.0.1 responselike: 3.0.0 + cacheable@2.3.1: + dependencies: + '@cacheable/memory': 2.0.7 + '@cacheable/utils': 2.3.3 + hookified: 1.15.0 + keyv: 5.5.5 + qified: 0.5.3 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -22826,6 +23038,8 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + colord@2.9.3: {} + colorette@2.0.20: {} colorjs.io@0.5.2: {} @@ -22925,6 +23139,15 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 + cosmiconfig@9.0.0(typescript@5.7.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.7.3 + croner@9.1.0: {} cross-env@7.0.3: @@ -22947,6 +23170,13 @@ snapshots: crypto-random-string@2.0.0: {} + css-functions-list@3.2.3: {} + + css-tree@3.1.0: + dependencies: + mdn-data: 2.12.2 + source-map-js: 1.2.1 + cssesc@3.0.0: {} cssfilter@0.0.10: {} @@ -23311,6 +23541,8 @@ snapshots: entities@6.0.1: {} + env-paths@2.2.1: {} + env-paths@3.0.0: optional: true @@ -24209,6 +24441,14 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -24233,6 +24473,8 @@ snapshots: dependencies: strnum: 2.1.1 + fastest-levenshtein@1.0.16: {} + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -24258,6 +24500,10 @@ snapshots: dependencies: is-unicode-supported: 2.1.0 + file-entry-cache@11.1.1: + dependencies: + flat-cache: 6.1.19 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -24332,8 +24578,16 @@ snapshots: flatted: 3.3.1 keyv: 4.5.4 + flat-cache@6.1.19: + dependencies: + cacheable: 2.3.1 + flatted: 3.3.3 + hookified: 1.15.0 + flatted@3.3.1: {} + flatted@3.3.3: {} + focus-trap@7.5.4: dependencies: tabbable: 6.2.0 @@ -24465,7 +24719,7 @@ snapshots: geist@1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: - next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) gel@2.0.1: dependencies: @@ -24606,6 +24860,10 @@ snapshots: is-windows: 1.0.2 resolve-dir: 1.0.1 + global-modules@2.0.0: + dependencies: + global-prefix: 3.0.0 + global-prefix@1.0.2: dependencies: expand-tilde: 2.0.2 @@ -24614,6 +24872,12 @@ snapshots: is-windows: 1.0.2 which: 1.3.1 + global-prefix@3.0.0: + dependencies: + ini: 1.3.8 + kind-of: 6.0.3 + which: 1.3.1 + globals@11.12.0: {} globals@14.0.0: {} @@ -24644,6 +24908,8 @@ snapshots: merge2: 1.4.1 slash: 4.0.0 + globjoin@0.1.4: {} + globrex@0.1.2: {} google-auth-library@9.14.2: @@ -24735,6 +25001,10 @@ snapshots: dependencies: has-symbols: 1.0.3 + hashery@1.4.0: + dependencies: + hookified: 1.15.0 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -24755,6 +25025,8 @@ snapshots: dependencies: parse-passwd: 1.0.0 + hookified@1.15.0: {} + hosted-git-info@2.8.9: {} html-encoding-sniffer@4.0.0: @@ -24765,6 +25037,8 @@ snapshots: html-escaper@2.0.2: {} + html-tags@3.3.1: {} + http-cache-semantics@4.1.1: {} http-errors@2.0.0: @@ -24842,6 +25116,8 @@ snapshots: ignore@5.3.2: {} + ignore@7.0.5: {} + image-size@2.0.2: {} immediate@3.0.6: {} @@ -25332,12 +25608,18 @@ snapshots: dependencies: json-buffer: 3.0.1 + keyv@5.5.5: + dependencies: + '@keyv/serialize': 1.1.1 + kind-of@6.0.3: {} kleur@3.0.3: {} kleur@4.1.5: {} + known-css-properties@0.37.0: {} + language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -25492,6 +25774,8 @@ snapshots: lodash.merge@4.6.2: {} + lodash.truncate@4.4.2: {} + lodash@4.17.21: {} log-update@6.1.0: @@ -25561,6 +25845,8 @@ snapshots: math-intrinsics@1.1.0: {} + mathml-tag-names@2.1.3: {} + mcp-handler@1.0.4(@modelcontextprotocol/sdk@1.24.3(zod@3.25.76))(next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: '@modelcontextprotocol/sdk': 1.24.3(zod@3.25.76) @@ -25631,12 +25917,16 @@ snapshots: dependencies: '@types/mdast': 4.0.4 + mdn-data@2.12.2: {} + media-typer@1.1.0: {} memoize-one@6.0.0: {} memory-pager@1.5.0: {} + meow@13.2.0: {} + merge-descriptors@2.0.0: {} merge-stream@2.0.0: {} @@ -26050,7 +26340,7 @@ snapshots: '@next/env': 13.5.11 fast-glob: 3.3.2 minimist: 1.2.8 - next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes@0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: @@ -26118,7 +26408,7 @@ snapshots: postcss: 8.4.31 react: 19.2.1 react-dom: 19.2.1(react@19.2.1) - styled-jsx: 5.1.6(react@19.2.1) + styled-jsx: 5.1.6(@babel/core@7.27.4)(react@19.2.1) optionalDependencies: '@next/swc-darwin-arm64': 15.4.8 '@next/swc-darwin-x64': 15.4.8 @@ -26137,32 +26427,6 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): - dependencies: - '@next/env': 15.4.10 - '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001720 - postcss: 8.4.31 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) - styled-jsx: 5.1.6(react@19.2.1) - optionalDependencies: - '@next/swc-darwin-arm64': 15.4.8 - '@next/swc-darwin-x64': 15.4.8 - '@next/swc-linux-arm64-gnu': 15.4.8 - '@next/swc-linux-arm64-musl': 15.4.8 - '@next/swc-linux-x64-gnu': 15.4.8 - '@next/swc-linux-x64-musl': 15.4.8 - '@next/swc-win32-arm64-msvc': 15.4.8 - '@next/swc-win32-x64-msvc': 15.4.8 - '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.56.1 - sass: 1.77.4 - sharp: 0.34.3 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - next@15.5.4(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4): dependencies: '@next/env': 15.5.4 @@ -26171,7 +26435,7 @@ snapshots: postcss: 8.4.31 react: 19.2.1 react-dom: 19.2.1(react@19.2.1) - styled-jsx: 5.1.6(react@19.2.1) + styled-jsx: 5.1.6(@babel/core@7.27.4)(react@19.2.1) optionalDependencies: '@next/swc-darwin-arm64': 15.5.4 '@next/swc-darwin-x64': 15.5.4 @@ -26660,30 +26924,40 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-import@15.1.0(postcss@8.5.5): + postcss-import@15.1.0(postcss@8.5.6): dependencies: - postcss: 8.5.5 + postcss: 8.5.6 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 - postcss-js@4.0.1(postcss@8.5.5): + postcss-js@4.0.1(postcss@8.5.6): dependencies: camelcase-css: 2.0.1 - postcss: 8.5.5 + postcss: 8.5.6 - postcss-load-config@4.0.2(postcss@8.5.5): + postcss-load-config@4.0.2(postcss@8.5.6): dependencies: lilconfig: 3.1.3 yaml: 2.6.0 optionalDependencies: - postcss: 8.5.5 + postcss: 8.5.6 - postcss-nested@6.2.0(postcss@8.5.5): + postcss-nested@6.2.0(postcss@8.5.6): dependencies: - postcss: 8.5.5 + postcss: 8.5.6 postcss-selector-parser: 6.1.2 + postcss-resolve-nested-selector@0.1.6: {} + + postcss-safe-parser@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-scss@4.0.9(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser@6.0.10: dependencies: cssesc: 3.0.0 @@ -26694,6 +26968,11 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + postcss-value-parser@4.2.0: {} postcss@8.4.31: @@ -26708,6 +26987,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postgres-array@2.0.0: {} postgres-array@3.0.2: {} @@ -26802,6 +27087,10 @@ snapshots: pure-rand@6.1.0: {} + qified@0.5.3: + dependencies: + hookified: 1.15.0 + qs-esm@7.0.2: {} qs@6.13.0: @@ -27152,6 +27441,8 @@ snapshots: resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} resolve@1.22.8: @@ -27724,6 +28015,12 @@ snapshots: is-plain-object: 5.0.0 tiny-warning: 1.0.3 + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + slice-ansi@5.0.0: dependencies: ansi-styles: 6.2.1 @@ -28056,10 +28353,50 @@ snapshots: optionalDependencies: '@babel/core': 7.27.4 - styled-jsx@5.1.6(react@19.2.1): + stylelint@16.26.1(typescript@5.7.3): dependencies: - client-only: 0.0.1 - react: 19.2.1 + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-syntax-patches-for-csstree': 1.0.22 + '@csstools/css-tokenizer': 3.0.4 + '@csstools/media-query-list-parser': 4.0.3(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + '@dual-bundle/import-meta-resolve': 4.2.1 + balanced-match: 2.0.0 + colord: 2.9.3 + cosmiconfig: 9.0.0(typescript@5.7.3) + css-functions-list: 3.2.3 + css-tree: 3.1.0 + debug: 4.4.3 + fast-glob: 3.3.3 + fastest-levenshtein: 1.0.16 + file-entry-cache: 11.1.1 + global-modules: 2.0.0 + globby: 11.1.0 + globjoin: 0.1.4 + html-tags: 3.3.1 + ignore: 7.0.5 + imurmurhash: 0.1.4 + is-plain-object: 5.0.0 + known-css-properties: 0.37.0 + mathml-tag-names: 2.1.3 + meow: 13.2.0 + micromatch: 4.0.8 + normalize-path: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-resolve-nested-selector: 0.1.6 + postcss-safe-parser: 7.0.1(postcss@8.5.6) + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + resolve-from: 5.0.0 + string-width: 4.2.3 + supports-hyperlinks: 3.2.0 + svg-tags: 1.0.0 + table: 6.9.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + - typescript stylis@4.2.0: {} @@ -28092,14 +28429,29 @@ snapshots: has-flag: 4.0.0 supports-color: 7.2.0 + supports-hyperlinks@3.2.0: + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + supports-preserve-symlinks-flag@1.0.0: {} + svg-tags@1.0.0: {} + swc-plugin-transform-remove-imports@8.3.0: {} symbol-tree@3.2.4: {} tabbable@6.2.0: {} + table@6.9.0: + dependencies: + ajv: 8.17.1 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + tailwind-merge@2.6.0: {} tailwindcss-animate@1.0.7(tailwindcss@3.4.17): @@ -28126,11 +28478,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.5 - postcss-import: 15.1.0(postcss@8.5.5) - postcss-js: 4.0.1(postcss@8.5.5) - postcss-load-config: 4.0.2(postcss@8.5.5) - postcss-nested: 6.2.0(postcss@8.5.5) + postcss: 8.5.6 + postcss-import: 15.1.0(postcss@8.5.6) + postcss-js: 4.0.1(postcss@8.5.6) + postcss-load-config: 4.0.2(postcss@8.5.6) + postcss-nested: 6.2.0(postcss@8.5.6) postcss-selector-parser: 6.1.2 resolve: 1.22.8 sucrase: 3.35.0 @@ -28848,7 +29200,7 @@ snapshots: esbuild: 0.25.5 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - postcss: 8.5.5 + postcss: 8.5.6 rollup: 4.52.3 tinyglobby: 0.2.15 optionalDependencies: @@ -28867,7 +29219,7 @@ snapshots: esbuild: 0.25.5 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - postcss: 8.5.5 + postcss: 8.5.6 rollup: 4.52.3 tinyglobby: 0.2.15 optionalDependencies: @@ -28886,7 +29238,7 @@ snapshots: esbuild: 0.25.5 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - postcss: 8.5.5 + postcss: 8.5.6 rollup: 4.52.3 tinyglobby: 0.2.15 optionalDependencies: @@ -29285,6 +29637,11 @@ snapshots: wrappy@1.0.2: {} + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@6.0.5): optionalDependencies: bufferutil: 4.0.8 From 8b3d8958a42d636a9a5a7ee9c2882ff89adb3180 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Mon, 5 Jan 2026 10:43:38 -0800 Subject: [PATCH 51/67] feat(richtext-lexical): adds docs page for lexical blocks, adds new lexical block component types and styles (#14971) Preview: https://payloadcms.com/docs/dynamic/rich-text/blocks?branch=docs/lexical-blocks This PR creates a new documentation page for lexical blocks, with lots of images and examples showing how to use the blocks feature and customize it. --- docs/rich-text/blocks.mdx | 500 ++++++++++++++++++ docs/rich-text/custom-features.mdx | 132 +---- docs/rich-text/official-features.mdx | 104 +--- .../blocks/client/componentInline/index.scss | 40 +- .../src/features/blocks/server/index.ts | 38 ++ packages/richtext-lexical/src/index.ts | 14 +- .../blockComponents/BlockComponent.tsx | 5 +- .../blockComponents/BlockComponentRSC.tsx | 4 +- .../blockComponents/LabelComponent.tsx | 4 +- .../inlineBlockComponents/BlockComponent.tsx | 4 +- .../inlineBlockComponents/LabelComponent.tsx | 4 +- 11 files changed, 592 insertions(+), 257 deletions(-) create mode 100644 docs/rich-text/blocks.mdx diff --git a/docs/rich-text/blocks.mdx b/docs/rich-text/blocks.mdx new file mode 100644 index 00000000000..c209eb15671 --- /dev/null +++ b/docs/rich-text/blocks.mdx @@ -0,0 +1,500 @@ +--- +title: Blocks +label: Blocks +order: 36 +desc: Using the BlocksFeature to add custom blocks and inline blocks to the Lexical editor +keywords: lexical, rich text, editor, blocks, inline blocks, custom blocks +--- + +The `BlocksFeature` allows you to embed Payload's [Blocks Field](/docs/fields/blocks) directly inside your Lexical rich text editor. This provides a powerful way to create structured, reusable content components within your rich text content. + + + Blocks within Lexical support the same features as standard Payload + blocks—including all field types, hooks, validation, access control, and + conditional logic. The only difference is that the data is stored within the + rich text JSON structure rather than as separate fields. + + +## Basic Setup + + + +To add blocks to your Lexical editor, include the `BlocksFeature` in your editor configuration: + +```ts +import { lexicalEditor, BlocksFeature } from '@payloadcms/richtext-lexical' + +{ + name: 'content', + type: 'richText', + editor: lexicalEditor({ + features: ({ defaultFeatures }) => [ + ...defaultFeatures, + BlocksFeature({ + blocks: [ + { + slug: 'banner', + fields: [ + { + name: 'style', + type: 'select', + options: ['info', 'warning', 'error', 'success'], + defaultValue: 'info', + }, + { + name: 'content', + type: 'textarea', + required: true, + }, + ], + }, + { + slug: 'cta', + fields: [ + { + name: 'heading', + type: 'text', + required: true, + }, + { + name: 'link', + type: 'text', + }, + ], + }, + ], + }), + ], + }), +} +``` + +Blocks use the same configuration schema as Blocks within Payload's [Blocks Field](/docs/fields/blocks). + +## Blocks vs Inline Blocks + + + +The `BlocksFeature` supports two types of blocks: + +### Blocks + +Regular blocks are **block-level elements** that take up an entire line, similar to paragraphs or headings. They cannot be placed inline with text. + +Use blocks for: + +- Call-to-action sections +- Image galleries +- Code snippets +- Embedded content (videos, maps) +- Any component that should stand alone + +### Inline Blocks + +Inline blocks can be **inserted within text**, appearing alongside other content in the same paragraph. They're useful for elements that need to flow with text. + +Use inline blocks for: + +- Mentions (@user) +- Custom badges or tags +- Inline icons or emojis +- Variable placeholders +- Footnote references + +```ts +BlocksFeature({ + // Block-level blocks + blocks: [ + { + slug: 'callout', + fields: [{ name: 'content', type: 'textarea' }], + }, + ], + // Inline blocks (appear within text) + inlineBlocks: [ + { + slug: 'mention', + fields: [ + { + name: 'user', + type: 'relationship', + relationTo: 'users', + required: true, + }, + ], + }, + ], +}) +``` + +## Data Structure + +Block data is stored within the Lexical JSON structure. Each block node contains a `fields` object with all the block's field values: + +```json +{ + "type": "block", + "version": 2, + "fields": { + "id": "65298b13db4ef8c744a7faaa", // default field (required, auto-generated) + "blockType": "banner", // default field (required, identifies the block) + "blockName": "Important Notice", // default field (optional, custom label for the block instance) + "style": "warning", // custom field + "content": "This is the block content..." // custom field + } +} +``` + +Inline blocks follow a similar structure with `type: "inlineBlock"`. + +## Custom Block Components + +You can customize how blocks appear in the editor by providing custom React components. This is useful when you want a more visual representation of your block content. + +### Block Components + + + +For regular blocks, use the `admin.components.Block` property to provide a custom component: + +```ts +{ + slug: 'myCustomBlock', + admin: { + components: { + Block: '/path/to/MyBlockComponent#MyBlockComponent', + }, + }, + fields: [ + { + name: 'style', + type: 'select', + options: ['primary', 'secondary'], + }, + ], +} +``` + +Your custom component can use composable primitives from `@payloadcms/richtext-lexical/client`. These components automatically receive block data from context, so you can use them to recreate the default block UI or arrange them in custom layouts: + +```tsx +'use client' +import type { LexicalBlockClientProps } from '@payloadcms/richtext-lexical' + +import { + BlockCollapsible, + BlockEditButton, + BlockRemoveButton, +} from '@payloadcms/richtext-lexical/client' +import { useFormFields } from '@payloadcms/ui' + +export const MyBlockComponent: React.FC = () => { + const style = useFormFields(([fields]) => fields.style) + + return ( + +
Style: {(style?.value as string) ?? 'none'}
+
+ You can manually render the remove and edit buttons if you want to: +
+
+ + +
+
+ ) +} +``` + +The `BlockCollapsible` component automatically renders an edit button that opens a drawer with the block's fields. You can customize this behavior by passing props like `removeButton={false}` to hide the default remove button and render it yourself. + +You can also choose to render something completely different in your custom block component: + + + +```tsx +'use client' +import type { LexicalBlockClientProps } from '@payloadcms/richtext-lexical' + +import { + BlockEditButton, + BlockRemoveButton, +} from '@payloadcms/richtext-lexical/client' +import { useFormFields } from '@payloadcms/ui' + +export const BlockComponent: React.FC = () => { + const content = useFormFields(([fields]) => fields.content) + + return ( +
+
+ ⚠️ Banner +
+ + +
+
+

{(content?.value as string) || 'No content'}

+
+ ) +} +``` + +### Inline Block Components + +For inline blocks, similar composable primitives are available: + + + +```tsx +'use client' +import type { LexicalInlineBlockClientProps } from '@payloadcms/richtext-lexical' + +import { + InlineBlockContainer, + InlineBlockEditButton, + InlineBlockLabel, + InlineBlockRemoveButton, +} from '@payloadcms/richtext-lexical/client' + +export const MyInlineBlockComponent: React.FC< + LexicalInlineBlockClientProps +> = () => { + return ( + + 1 + + 2 + + 3 + + + ) +} +``` + +Or, you can choose to render something completely different in your custom inline block component, for example a badge with a username: + + + +```tsx +'use client' +import type { LexicalInlineBlockClientProps } from '@payloadcms/richtext-lexical' + +import { + InlineBlockEditButton, + InlineBlockRemoveButton, +} from '@payloadcms/richtext-lexical/client' +import { useFormFields } from '@payloadcms/ui' + +export const MyInlineBlockComponent: React.FC< + LexicalInlineBlockClientProps +> = () => { + const username = useFormFields(([fields]) => fields.username) + + return ( +
+ @{(username?.value as string) || 'username'} +
+ + +
+
+ ) +} +``` + +### Label Components + +You can also customize the label shown in the block header using `admin.components.Label`. This is useful for displaying dynamic information based on the block's field values. + +**Block Label:** + + + +```tsx +'use client' +import type { LexicalBlockLabelClientProps } from '@payloadcms/richtext-lexical' + +import { useFormFields } from '@payloadcms/ui' + +export const MyBlockLabel: React.FC = () => { + const title = useFormFields(([fields]) => fields.title) + + return ( +
+ Custom Label. Value of title field: {title?.value as string} +
+ ) +} +``` + +**Inline Block Label:** + + + +```tsx +'use client' +import type { LexicalInlineBlockLabelClientProps } from '@payloadcms/richtext-lexical' + +import { useFormFields } from '@payloadcms/ui' + +export const MyInlineBlockLabel: React.FC< + LexicalInlineBlockLabelClientProps +> = () => { + const name = useFormFields(([fields]) => fields.name) + + return ( + + Custom Label. Name field: {name?.value as string} + + ) +} +``` + +### Example: Pre-made CodeBlock + +For a real-world example of a custom block component, see the [source code for Payload's pre-made CodeBlock](https://github.com/payloadcms/payload/blob/main/packages/richtext-lexical/src/features/blocks/premade/CodeBlock/index.ts). It's a standard block with a custom `admin.components.Block` component that uses the same APIs documented above—including `useFormFields`, `BlockCollapsible`, and the helper buttons. + +### TypeScript + +When building custom block components, you can import the following types for proper typing: + +```ts +import type { + // Block component types + LexicalBlockClientProps, + LexicalBlockServerProps, + + // Block label component types + LexicalBlockLabelClientProps, + LexicalBlockLabelServerProps, + + // Inline block component types + LexicalInlineBlockClientProps, + LexicalInlineBlockServerProps, + + // Inline block label component types + LexicalInlineBlockLabelClientProps, + LexicalInlineBlockLabelServerProps, +} from '@payloadcms/richtext-lexical' +``` + +| Type | Use Case | +| ---------------------------------------- | ---------------------------------------------------- | +| **`LexicalBlockClientProps`** | Client component for `admin.components.Block` | +| **`LexicalBlockServerProps`** | Server component for `admin.components.Block` | +| **`LexicalBlockLabelClientProps`** | Client component for `admin.components.Label` | +| **`LexicalBlockLabelServerProps`** | Server component for `admin.components.Label` | +| **`LexicalInlineBlockClientProps`** | Client component for inline `admin.components.Block` | +| **`LexicalInlineBlockServerProps`** | Server component for inline `admin.components.Block` | +| **`LexicalInlineBlockLabelClientProps`** | Client component for inline `admin.components.Label` | +| **`LexicalInlineBlockLabelServerProps`** | Server component for inline `admin.components.Label` | + +## Rendering Blocks + +When rendering rich text content on the frontend, blocks need to be handled by your converter configuration. See the following guides for details: + +- [JSX Converters](/docs/rich-text/converting-jsx#lexical-blocks) - For React/Next.js applications +- [HTML Converters](/docs/rich-text/converting-html#blocks-to-html) - For static HTML output +- [Markdown Converters](/docs/rich-text/converting-markdown#defining-a-custom-block) - For markdown output + +Each converter allows you to define custom renderers for your block types, giving you full control over how block content appears on your frontend. + +## Code Block + + + +Payload provides a pre-built `CodeBlock` that you can use directly in your projects. It includes syntax highlighting, language selection, and optional TypeScript type definitions support: + +```ts +import { BlocksFeature, CodeBlock } from '@payloadcms/richtext-lexical' + +BlocksFeature({ + blocks: [ + CodeBlock({ + defaultLanguage: 'ts', + languages: { + plaintext: 'Plain Text', + js: 'JavaScript', + ts: 'TypeScript', + tsx: 'TSX', + jsx: 'JSX', + }, + }), + ], +}) +``` + +### CodeBlock Options + +| Option | Description | +| --------------------- | ----------------------------------------------------------------- | +| **`slug`** | Override the block slug. Default: `'Code'` | +| **`defaultLanguage`** | The default language selection. Default: first key in `languages` | +| **`languages`** | Object mapping language keys to display labels | +| **`typescript`** | TypeScript-specific configuration (see below) | +| **`fieldOverrides`** | Partial block config to override or extend the default CodeBlock | + +### TypeScript Support + +When using TypeScript as a language option, you can load external type definitions to provide IntelliSense in the editor: + +```ts +CodeBlock({ + slug: 'PayloadCode', + languages: { + ts: 'TypeScript', + }, + typescript: { + fetchTypes: [ + { + // In the url you can use @latest or a specific version (e.g. @3.68.5) + url: 'https://unpkg.com/payload@latest/dist/index.bundled.d.ts', + filePath: 'file:///node_modules/payload/index.d.ts', + }, + { + url: 'https://unpkg.com/@types/react@latest/index.d.ts', + filePath: 'file:///node_modules/@types/react/index.d.ts', + }, + ], + paths: { + payload: ['file:///node_modules/payload/index.d.ts'], + react: ['file:///node_modules/@types/react/index.d.ts'], + }, + typeRoots: ['node_modules/@types', 'node_modules/payload'], + enableSemanticValidation: true, + }, +}) +``` + +| TypeScript Option | Description | +| ------------------------------ | ------------------------------------------------------------------------------ | +| **`fetchTypes`** | Array of `{ url, filePath }` objects to fetch external type definitions | +| **`paths`** | Module path mappings for import resolution | +| **`typeRoots`** | Directories to search for type definitions. Default: `['node_modules/@types']` | +| **`target`** | TypeScript compilation target. Default: `'ESNext'` | +| **`enableSemanticValidation`** | Enable full type checking (not just syntax). Default: `false` | diff --git a/docs/rich-text/custom-features.mdx b/docs/rich-text/custom-features.mdx index f25fd327e78..5fdef6a1e32 100644 --- a/docs/rich-text/custom-features.mdx +++ b/docs/rich-text/custom-features.mdx @@ -28,137 +28,7 @@ Before you start building a custom feature, consider whether you can achieve you Using the BlocksFeature, you can add both inline blocks (= can be inserted into a paragraph, in between text) and block blocks (= take up the whole line) to the editor. If you simply want to bring custom react components into the editor, this is the way to go. -### Example: Code Field Block with language picker - -This example demonstrates how to create a custom code field block with a language picker using the `BlocksFeature`. First, make sure to explicitly install `@payloadcms/ui` in your project. - -Field Config: - -```ts -import { - BlocksFeature, - lexicalEditor, -} from '@payloadcms/richtext-lexical' - -export const languages = { - ts: 'TypeScript', - plaintext: 'Plain Text', - tsx: 'TSX', - js: 'JavaScript', - jsx: 'JSX', -} - -// ... -{ - name: 'richText', - type: 'richText', - editor: lexicalEditor({ - features: ({ defaultFeatures }) => [ - ...defaultFeatures, - BlocksFeature({ - blocks: [ - { - slug: 'Code', - fields: [ - { - type: 'select', - name: 'language', - options: Object.entries(languages).map(([key, value]) => ({ - label: value, - value: key, - })), - defaultValue: 'ts', - }, - { - admin: { - components: { - Field: './path/to/CodeComponent#Code', - }, - }, - name: 'code', - type: 'code', - }, - ], - } - ], - inlineBlocks: [], - }), - ], - }), -}, -``` - -CodeComponent.tsx: - -```tsx -'use client' -import type { CodeFieldClient, CodeFieldClientProps } from 'payload' - -import { CodeField, useFormFields } from '@payloadcms/ui' -import React, { useMemo } from 'react' - -import { languages } from './yourFieldConfig' - -const languageKeyToMonacoLanguageMap = { - plaintext: 'plaintext', - ts: 'typescript', - tsx: 'typescript', -} - -type Language = keyof typeof languageKeyToMonacoLanguageMap - -export const Code: React.FC = ({ - autoComplete, - field, - forceRender, - path, - permissions, - readOnly, - renderedBlocks, - schemaPath, - validate, -}) => { - const languageField = useFormFields(([fields]) => fields['language']) - - const language: Language = - (languageField?.value as Language) || - (languageField?.initialValue as Language) || - 'ts' - - const label = languages[language] - - const props: CodeFieldClient = useMemo( - () => ({ - ...field, - type: 'code', - admin: { - ...field.admin, - editorOptions: undefined, - language: languageKeyToMonacoLanguageMap[language] || language, - }, - label, - }), - [field, language, label], - ) - - const key = `${field.name}-${language}-${label}` - - return ( - - ) -} -``` +For detailed documentation on the BlocksFeature, including custom block components and examples, see the [Blocks documentation](/docs/rich-text/blocks). ## Server Feature diff --git a/docs/rich-text/official-features.mdx b/docs/rich-text/official-features.mdx index d31b7fa32bf..91e8797be64 100644 --- a/docs/rich-text/official-features.mdx +++ b/docs/rich-text/official-features.mdx @@ -399,110 +399,10 @@ FixedToolbarFeature({ ### BlocksFeature -- Description: Allows use of Payload's Blocks Field directly in the editor with toolbar buttons and slash menu entries for each block type. +- Description: Allows use of Payload's [Blocks Field](/docs/fields/blocks) directly in the editor with toolbar buttons and slash menu entries for each block type. Supports both block-level and inline blocks. - Included by default: No -- Types: - -```ts -type BlocksFeatureProps = { - blocks?: (Block | BlockSlug)[] | Block[] - inlineBlocks?: (Block | BlockSlug)[] | Block[] -} -``` - -- Usage example: - -```ts -BlocksFeature({ - blocks: [ - { - slug: 'callout', - fields: [ - { - name: 'text', - type: 'text', - required: true, - }, - ], - }, - ], - inlineBlocks: [ - { - slug: 'mention', - fields: [ - { - name: 'name', - type: 'text', - required: true, - }, - ], - }, - ], -}) -``` - -#### Code Blocks - -Payload exports a premade CodeBlock that you can import and use in your project. It supports syntax highlighting, dynamically selecting the language and loading in external type definitions: - -```ts -import { BlocksFeature, CodeBlock } from '@payloadcms/richtext-lexical' - -// ... -BlocksFeature({ - blocks: [ - CodeBlock({ - defaultLanguage: 'ts', - languages: { - js: 'JavaScript', - plaintext: 'Plain Text', - ts: 'TypeScript', - }, - }), - ], -}), -// ... -``` - -When using TypeScript, you can also pass in additional type definitions that will be available in the editor. Here's an example of how to make `payload` and `react` available in the editor: -```ts -import { BlocksFeature, CodeBlock } from '@payloadcms/richtext-lexical' - -// ... -BlocksFeature({ - blocks: [ - CodeBlock({ - slug: 'PayloadCode', - languages: { - ts: 'TypeScript', - }, - typescript: { - fetchTypes: [ - { - // The index.bundled.d.ts contains all the types for Payload in one file, so that Monaco doesn't need to fetch multiple files. - // This file may be removed in the future and is not guaranteed to be available in future versions of Payload. - url: 'https://unpkg.com/payload@3.59.0-internal.8435f3c/dist/index.bundled.d.ts', - filePath: 'file:///node_modules/payload/index.d.ts', - }, - { - url: 'https://unpkg.com/@types/react@19.1.17/index.d.ts', - filePath: 'file:///node_modules/@types/react/index.d.ts', - }, - ], - paths: { - payload: ['file:///node_modules/payload/index.d.ts'], - react: ['file:///node_modules/@types/react/index.d.ts'], - }, - typeRoots: ['node_modules/@types', 'node_modules/payload'], - // Enable type checking. By default, only syntax checking is enabled. - enableSemanticValidation: true, - }, - }), - ], -}), -// ... -``` +For complete documentation including custom block components, the pre-built CodeBlock, and rendering blocks on the frontend, see the dedicated [Blocks documentation](/docs/rich-text/blocks). ### TreeViewFeature diff --git a/packages/richtext-lexical/src/features/blocks/client/componentInline/index.scss b/packages/richtext-lexical/src/features/blocks/client/componentInline/index.scss index 020f403309c..a8315e4531e 100644 --- a/packages/richtext-lexical/src/features/blocks/client/componentInline/index.scss +++ b/packages/richtext-lexical/src/features/blocks/client/componentInline/index.scss @@ -2,22 +2,36 @@ @layer payload-default { .LexicalEditorTheme__inlineBlock { - @extend %body; - @include shadow-sm; display: inline-block; - margin-right: base(0.2); - margin-left: base(0.2); - padding: base(0.1); - padding-inline-start: base(0.4); - background: var(--theme-input-bg); - outline: 1px solid var(--theme-elevation-100); - border-radius: $style-radius-s; - max-width: calc(var(--base) * 15); - font-family: var(--font-body); + + &.decorator-selected { + box-shadow: unset !important; + outline: unset !important; + + .LexicalEditorTheme__inlineBlock__container { + box-shadow: $focus-box-shadow; + outline: none; + } + } &__container { + @extend %body; + @include shadow-sm; + margin-right: base(0.2); + margin-left: base(0.2); + padding: base(0.1); + padding-inline-start: base(0.4); + background: var(--theme-input-bg); + outline: 1px solid var(--theme-elevation-100); + border-radius: $style-radius-s; + max-width: calc(var(--base) * 15); + font-family: var(--font-body); display: flex; align-items: center; + + &:hover { + outline: 1px solid var(--theme-elevation-150); + } } &-not-found { @@ -29,10 +43,6 @@ background: transparent; } - &:hover { - outline: 1px solid var(--theme-elevation-150); - } - &__wrap { flex-grow: 1; overflow: hidden; diff --git a/packages/richtext-lexical/src/features/blocks/server/index.ts b/packages/richtext-lexical/src/features/blocks/server/index.ts index e3fec983cd5..effc4975f6e 100644 --- a/packages/richtext-lexical/src/features/blocks/server/index.ts +++ b/packages/richtext-lexical/src/features/blocks/server/index.ts @@ -5,6 +5,8 @@ import type { Config, FieldSchemaMap, FlattenedBlocksField, + UIFieldClientProps, + UIFieldServerProps, } from 'payload' import { fieldsToJSONSchema, flattenAllFields, sanitizeFields } from 'payload' @@ -275,3 +277,39 @@ export const BlocksFeature = createServerFeature { +export const BlockComponent: React.FC = () => { const key = useFormFields(([fields]) => fields.key) return ( diff --git a/test/lexical/collections/Lexical/blockComponents/BlockComponentRSC.tsx b/test/lexical/collections/Lexical/blockComponents/BlockComponentRSC.tsx index 673196ff691..9827637becd 100644 --- a/test/lexical/collections/Lexical/blockComponents/BlockComponentRSC.tsx +++ b/test/lexical/collections/Lexical/blockComponents/BlockComponentRSC.tsx @@ -1,9 +1,9 @@ -import type { UIFieldServerComponent } from 'payload' +import type { LexicalBlockServerProps } from '@payloadcms/richtext-lexical' import { BlockCollapsible } from '@payloadcms/richtext-lexical/client' import React from 'react' -export const BlockComponentRSC: UIFieldServerComponent = (props) => { +export const BlockComponentRSC: React.FC = (props) => { const { siblingData } = props return Data: {siblingData?.key ?? ''} diff --git a/test/lexical/collections/Lexical/blockComponents/LabelComponent.tsx b/test/lexical/collections/Lexical/blockComponents/LabelComponent.tsx index 92e0d5c2df3..a7a9e3c30dc 100644 --- a/test/lexical/collections/Lexical/blockComponents/LabelComponent.tsx +++ b/test/lexical/collections/Lexical/blockComponents/LabelComponent.tsx @@ -1,11 +1,11 @@ 'use client' -import type { UIFieldClientComponent } from 'payload' +import type { LexicalBlockLabelClientProps } from '@payloadcms/richtext-lexical' import { useFormFields } from '@payloadcms/ui' import React from 'react' -export const LabelComponent: UIFieldClientComponent = () => { +export const LabelComponent: React.FC = () => { const key = useFormFields(([fields]) => fields.key) return
{(key?.value as string) ?? ''}yaya
diff --git a/test/lexical/collections/Lexical/inlineBlockComponents/BlockComponent.tsx b/test/lexical/collections/Lexical/inlineBlockComponents/BlockComponent.tsx index 786cb37714d..31f08d55ccf 100644 --- a/test/lexical/collections/Lexical/inlineBlockComponents/BlockComponent.tsx +++ b/test/lexical/collections/Lexical/inlineBlockComponents/BlockComponent.tsx @@ -1,3 +1,5 @@ +import type { LexicalInlineBlockServerProps } from '@payloadcms/richtext-lexical' + import { InlineBlockContainer, InlineBlockEditButton, @@ -6,7 +8,7 @@ import { } from '@payloadcms/richtext-lexical/client' import React from 'react' -export const BlockComponent: React.FC = () => { +export const BlockComponent: React.FC = () => { return (

Test

diff --git a/test/lexical/collections/Lexical/inlineBlockComponents/LabelComponent.tsx b/test/lexical/collections/Lexical/inlineBlockComponents/LabelComponent.tsx index 9364e90ce28..3780bb948d6 100644 --- a/test/lexical/collections/Lexical/inlineBlockComponents/LabelComponent.tsx +++ b/test/lexical/collections/Lexical/inlineBlockComponents/LabelComponent.tsx @@ -1,9 +1,11 @@ 'use client' +import type { LexicalInlineBlockClientProps } from '@payloadcms/richtext-lexical' + import { useFormFields } from '@payloadcms/ui' import React from 'react' -export const LabelComponent: React.FC = () => { +export const LabelComponent: React.FC = () => { const key = useFormFields(([fields]) => fields.key) return
{(key?.value as string) ?? ''}yaya
From c22988905eb92fc77668ee7a91e6f070bec35ce5 Mon Sep 17 00:00:00 2001 From: Sean Zubrickas Date: Mon, 5 Jan 2026 13:56:46 -0500 Subject: [PATCH 52/67] chore: adds comment in image component (#14663) Fixes #12105 --- .../src/components/Media/ImageMedia/index.tsx | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/templates/website/src/components/Media/ImageMedia/index.tsx b/templates/website/src/components/Media/ImageMedia/index.tsx index 8a1dc106471..0caf826e72f 100644 --- a/templates/website/src/components/Media/ImageMedia/index.tsx +++ b/templates/website/src/components/Media/ImageMedia/index.tsx @@ -17,6 +17,34 @@ const { breakpoints } = cssVariables const placeholderBlur = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABchJREFUWEdtlwtTG0kMhHtGM7N+AAdcDsjj///EBLzenbtuadbLJaZUTlHB+tRqSesETB3IABqQG1KbUFqDlQorBSmboqeEBcC1d8zrCixXYGZcgMsFmH8B+AngHdurAmXKOE8nHOoBrU6opcGswPi5KSP9CcBaQ9kACJH/ALAA1xm4zMD8AczvQCcAQeJVAZsy7nYApTSUzwCHUKACeUJi9TsFci7AHmDtuHYqQIC9AgQYKnSwNAig4NyOOwXq/xU47gDYggarjIpsRSEA3Fqw7AGkwgW4fgALAdiC2btKgNZwbgdMbEFpqFR2UyCR8xwAhf8bUHIGk1ckMyB5C1YkeWAdAPQBAeiD6wVYPoD1HUgXwFagZAGc6oSpTmilopoD5GzISQD3odcNIFca0BUQQM5YA2DpHV0AYURBDIAL0C+ugC0C4GedSsVUmwC8/4w8TPiwU6AClJ5RWL1PgQNkrABWdKB3YF3cBwRY5lsI4ApkKpCQi+FIgFJU/TDgDuAxAAwonJuKpGD1rkCXCR1ALyrAUSSEQAhwBdYZ6DPAgSUA2c1wKIZmRcHxMzMYR9DH8NlbkAwwApSAcABwBwTAbb6owAr0AFiZPILVEyCtMmK2jCkTwFDNUNj7nJETQx744gCUmgkZVGJUHyakEZE4W91jtGFA9KsD8Z3JFYDlhGYZLWcllwJMnplcPy+csFAgAAaIDOgeuAGoB96GLZg4kmtfMjnr6ig5oSoySsoy3ya/FMivXZWxwr0KIf9nACbfqcBEgmBSAtAlIT83R+70IWpyACamIjf5E1Iqb9ECVmnoI/FvAIRk8s2J0Y5IquQDgB+5wpScw5AUTC75VTmTs+72NUzoCvQIaAXv5Q8PDAZKLD+MxLv3RFE7KlsQChgBIlKiCv5ByaZv3gJZNm8AnVMhAN+EjrtTYQMICJpu6/0aiQnhClANlz+Bw0cIWa8ev0sBrtrhAyaXEnrfGfATQJiRKih5vKeOHNXXPFrgyamAADh0Q4F2/sESojomDS9o9k0b0H83xjB8qL+JNoTjN+enjpaBpingRh4e8MSugudM030A8FeqMI6PFIgNyPehkpZWGFEAARIQdH5LcAAqIACHkAJqg4OoBccHAuz76wr4BbzFOEa8iBuAZB8AtJHLP2VgMgJw/EIBowo7HxCAH3V6dAXEE/vZ5aZIA8BP8RKhm7Cp8BnAMnAQADdgQDA520AVIpScP+enHz0Gwp25h4i2dPg5FkDXrbsdJikQwXuWgaM5gEMk1AgH4DKKFjDf3bMD+FjEeIxLlRKYnBk2BbquvSDCAQ4gwZiMAAmH4gBTyRtEsYxi7gP6QSrc//39BrDNqG8rtYTmC4BV1SfMhOhaumFCT87zy4pPhQBZEK1kQVRjJBBi7AOlePgyAPYjwlvtagx9e/dnQraAyS894TIkkAIEYMKEc8k4EqJ68lZ5jjNqcQC2QteQOf7659umwBgPybNtK4dg9WvnMyFwXYGP7uEO1lwJgAnPNeMYMVXbIIYKFioI4PGFt+BWPVfmWJdjW2lTUnLGCswECAgaUy86iwA1464ajo0QhgMBFGyBoZahANsMpMfXr1JA1SN29m5lqgXj+UPV85uRA7yv/KYUO4Tk7Hc1AZwbIRzg0AyNj2UlAMwfSLSMnl7fdAbcxHuA27YaAMvaQ4GOjwX4RTUGAG8Ge14N963g1AynqUiFqRX9noasxT4b8entNRQYyamk/3tYcHsO7R3XJRRYOn4tw4iUnwBM5gDnySGOreAwAGo8F9IDHEcq8Pz2Kg/oXCpuIL6tOPD8LsDn0ABYQoGFRowlsAEUPPDrGAGowAbgKsgDMmE8mDy/vXQ9IAwI7u4wta+gAdAdgB64Ah9SgD4IgGKhwACoAjgNgFDhtxY8f33ZTMjqdTAiHMBPrn8ZWkEfzFdX4Oc1AHg3+ADbvN8PU8WdFKg4Tt6CQy2+D4YHaMT/JP4XzbAq98cPDIUAAAAASUVORK5CYII=' +/** + * ImageMedia + * + * This component passes a **relative** `src` (e.g. `/media/...`) to Next.js Image. + * The `getMediaUrl` utility constructs the full URL by prepending the base URL from env vars + * (NEXT_PUBLIC_SERVER_URL). Next.js then optimizes this using `remotePatterns` configured + * in next.config.js — no custom `loader` needed. + * + * Flow: + * 1. Resource URL from Payload: `/media/image-123.jpg` + * 2. getMediaUrl() adds base URL: `https://yourdomain.com/media/image-123.jpg` + * 3. Next.js Image optimizes via remotePatterns: `/_next/image?url=...&w=1200&q=75` + * + * If your storage/plugin returns **external CDN URLs** (e.g. `https://cdn.example.com/...`), + * choose ONE of the following: + * A) Allow the remote host in next.config.js: + * images: { remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }] } + * B) Provide a **custom loader** for CDN-specific transforms: + * const imageLoader: ImageLoader = ({ src, width, quality }) => + * `https://cdn.example.com${src}?w=${width}&q=${quality ?? 75}` + * + * C) Skip optimization: + * + * + * TL;DR: Template uses relative URLs + getMediaUrl() to construct full URLs, then relies on + * remotePatterns for optimization. Only add `loader` if using external CDNs with custom transforms. + */ + export const ImageMedia: React.FC = (props) => { const { alt: altFromProps, From 777c72b2661e7cf8134c97db75ee40140826c67e Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Mon, 5 Jan 2026 11:05:42 -0800 Subject: [PATCH 53/67] chore(deps): bump dnd-kit (#15083) Fixes https://github.com/payloadcms/payload/issues/15059 This bumps all dnd-kit dependencies, which fixes peer dependency issues between `@dnd-kit/core` and `@dnd-kit/modifiers` --- packages/next/package.json | 4 +-- packages/ui/package.json | 4 +-- pnpm-lock.yaml | 62 ++++++++++++++++++++------------------ 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/packages/next/package.json b/packages/next/package.json index c132714303e..9b5ccdabf00 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -108,9 +108,9 @@ ] }, "dependencies": { - "@dnd-kit/core": "6.0.8", + "@dnd-kit/core": "6.3.1", "@dnd-kit/modifiers": "9.0.0", - "@dnd-kit/sortable": "7.0.2", + "@dnd-kit/sortable": "10.0.0", "@payloadcms/graphql": "workspace:*", "@payloadcms/translations": "workspace:*", "@payloadcms/ui": "workspace:*", diff --git a/packages/ui/package.json b/packages/ui/package.json index 71f7784f092..9c402e9c47e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -138,8 +138,8 @@ }, "dependencies": { "@date-fns/tz": "1.2.0", - "@dnd-kit/core": "6.0.8", - "@dnd-kit/sortable": "7.0.2", + "@dnd-kit/core": "6.3.1", + "@dnd-kit/sortable": "10.0.0", "@dnd-kit/utilities": "3.2.2", "@faceless-ui/modal": "3.0.0", "@faceless-ui/scroll-info": "2.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c15ce34dde..b3afdeaf5ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -751,14 +751,14 @@ importers: packages/next: dependencies: '@dnd-kit/core': - specifier: 6.0.8 - version: 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + specifier: 6.3.1 + version: 6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@dnd-kit/modifiers': specifier: 9.0.0 - version: 9.0.0(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) + version: 9.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) '@dnd-kit/sortable': - specifier: 7.0.2 - version: 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) + specifier: 10.0.0 + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) '@payloadcms/graphql': specifier: workspace:* version: link:../graphql @@ -1716,11 +1716,11 @@ importers: specifier: 1.2.0 version: 1.2.0 '@dnd-kit/core': - specifier: 6.0.8 - version: 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + specifier: 6.3.1 + version: 6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@dnd-kit/sortable': - specifier: 7.0.2 - version: 7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) + specifier: 10.0.0 + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1) '@dnd-kit/utilities': specifier: 3.2.2 version: 3.2.2(react@19.2.1) @@ -1859,7 +1859,7 @@ importers: version: 16.8.1 next: specifier: 15.4.10 - version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) payload: specifier: workspace:* version: link:../../packages/payload @@ -2200,7 +2200,7 @@ importers: version: 16.4.7 geist: specifier: ^1.3.0 - version: 1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 1.4.2(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) graphql: specifier: 16.8.1 version: 16.8.1 @@ -2209,10 +2209,10 @@ importers: version: 0.378.0(react@19.2.1) next: specifier: 15.4.10 - version: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + version: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-sitemap: specifier: ^4.2.3 - version: 4.2.3(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) + version: 4.2.3(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)) payload: specifier: workspace:* version: link:../../packages/payload @@ -4010,13 +4010,13 @@ packages: resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} - '@dnd-kit/accessibility@3.1.0': - resolution: {integrity: sha512-ea7IkhKvlJUv9iSHJOnxinBcoOI3ppGnnL+VDJ75O45Nss6HtZd8IdN8touXPDtASfeI2T2LImb8VOZcL47wjQ==} + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} peerDependencies: react: 19.2.1 - '@dnd-kit/core@6.0.8': - resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} + '@dnd-kit/core@6.3.1': + resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} peerDependencies: react: 19.2.1 react-dom: 19.2.1 @@ -4027,10 +4027,10 @@ packages: '@dnd-kit/core': ^6.3.0 react: 19.2.1 - '@dnd-kit/sortable@7.0.2': - resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==} + '@dnd-kit/sortable@10.0.0': + resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==} peerDependencies: - '@dnd-kit/core': ^6.0.7 + '@dnd-kit/core': ^6.3.0 react: 19.2.1 '@dnd-kit/utilities@3.2.2': @@ -17480,29 +17480,29 @@ snapshots: '@discoveryjs/json-ext@0.5.7': {} - '@dnd-kit/accessibility@3.1.0(react@19.2.1)': + '@dnd-kit/accessibility@3.1.1(react@19.2.1)': dependencies: react: 19.2.1 tslib: 2.8.1 - '@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': + '@dnd-kit/core@6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1)': dependencies: - '@dnd-kit/accessibility': 3.1.0(react@19.2.1) + '@dnd-kit/accessibility': 3.1.1(react@19.2.1) '@dnd-kit/utilities': 3.2.2(react@19.2.1) react: 19.2.1 react-dom: 19.2.1(react@19.2.1) tslib: 2.8.1 - '@dnd-kit/modifiers@9.0.0(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': + '@dnd-kit/modifiers@9.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/core': 6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@dnd-kit/utilities': 3.2.2(react@19.2.1) react: 19.2.1 tslib: 2.8.1 - '@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': + '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react@19.2.1)': dependencies: - '@dnd-kit/core': 6.0.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + '@dnd-kit/core': 6.3.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) '@dnd-kit/utilities': 3.2.2(react@19.2.1) react: 19.2.1 tslib: 2.8.1 @@ -24717,6 +24717,10 @@ snapshots: - encoding - supports-color + geist@1.4.2(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + dependencies: + next: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + geist@1.4.2(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) @@ -26334,13 +26338,13 @@ snapshots: transitivePeerDependencies: - supports-color - next-sitemap@4.2.3(next@15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): + next-sitemap@4.2.3(next@15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4)): dependencies: '@corex/deepmerge': 4.0.43 '@next/env': 13.5.11 fast-glob: 3.3.2 minimist: 1.2.8 - next: 15.4.10(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(babel-plugin-react-compiler@19.1.0-rc.3)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) + next: 15.4.10(@babel/core@7.27.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.56.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(sass@1.77.4) next-themes@0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1): dependencies: From d29d968900dba4621da8a465c047557b5b983aee Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Mon, 5 Jan 2026 15:00:47 -0500 Subject: [PATCH 54/67] chore(release): v3.70.0 [skip ci] --- package.json | 2 +- packages/admin-bar/package.json | 2 +- packages/create-payload-app/package.json | 2 +- packages/db-d1-sqlite/package.json | 2 +- packages/db-mongodb/package.json | 2 +- packages/db-postgres/package.json | 2 +- packages/db-sqlite/package.json | 2 +- packages/db-vercel-postgres/package.json | 2 +- packages/drizzle/package.json | 2 +- packages/email-nodemailer/package.json | 2 +- packages/email-resend/package.json | 2 +- packages/graphql/package.json | 2 +- packages/kv-redis/package.json | 2 +- packages/live-preview-react/package.json | 2 +- packages/live-preview-vue/package.json | 2 +- packages/live-preview/package.json | 2 +- packages/next/package.json | 2 +- packages/payload-cloud/package.json | 2 +- packages/payload/package.json | 2 +- packages/plugin-cloud-storage/package.json | 2 +- packages/plugin-ecommerce/package.json | 2 +- packages/plugin-form-builder/package.json | 2 +- packages/plugin-import-export/package.json | 2 +- packages/plugin-mcp/package.json | 2 +- packages/plugin-multi-tenant/package.json | 2 +- packages/plugin-nested-docs/package.json | 2 +- packages/plugin-redirects/package.json | 2 +- packages/plugin-search/package.json | 2 +- packages/plugin-sentry/package.json | 2 +- packages/plugin-seo/package.json | 2 +- packages/plugin-stripe/package.json | 2 +- packages/richtext-lexical/package.json | 2 +- packages/richtext-slate/package.json | 2 +- packages/sdk/package.json | 2 +- packages/storage-azure/package.json | 2 +- packages/storage-gcs/package.json | 2 +- packages/storage-r2/package.json | 2 +- packages/storage-s3/package.json | 2 +- packages/storage-uploadthing/package.json | 2 +- packages/storage-vercel-blob/package.json | 2 +- packages/translations/package.json | 2 +- packages/ui/package.json | 2 +- 42 files changed, 42 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 27e54f9cacb..34df3b677a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload-monorepo", - "version": "3.69.0", + "version": "3.70.0", "private": true, "type": "module", "workspaces": [ diff --git a/packages/admin-bar/package.json b/packages/admin-bar/package.json index 2471a6fa6e2..c8dfd15d070 100644 --- a/packages/admin-bar/package.json +++ b/packages/admin-bar/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/admin-bar", - "version": "3.69.0", + "version": "3.70.0", "description": "An admin bar for React apps using Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/create-payload-app/package.json b/packages/create-payload-app/package.json index 2cd28a8ca54..a7c5fe01553 100644 --- a/packages/create-payload-app/package.json +++ b/packages/create-payload-app/package.json @@ -1,6 +1,6 @@ { "name": "create-payload-app", - "version": "3.69.0", + "version": "3.70.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/db-d1-sqlite/package.json b/packages/db-d1-sqlite/package.json index d3fcfc6a2fb..a1da294009b 100644 --- a/packages/db-d1-sqlite/package.json +++ b/packages/db-d1-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-d1-sqlite", - "version": "3.69.0", + "version": "3.70.0", "description": "The officially supported D1 SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-mongodb/package.json b/packages/db-mongodb/package.json index 728988f1d1e..338d151e262 100644 --- a/packages/db-mongodb/package.json +++ b/packages/db-mongodb/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-mongodb", - "version": "3.69.0", + "version": "3.70.0", "description": "The officially supported MongoDB database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-postgres/package.json b/packages/db-postgres/package.json index ecead2a66dc..4c36a194181 100644 --- a/packages/db-postgres/package.json +++ b/packages/db-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-postgres", - "version": "3.69.0", + "version": "3.70.0", "description": "The officially supported Postgres database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-sqlite/package.json b/packages/db-sqlite/package.json index efe7db13be9..49f86994716 100644 --- a/packages/db-sqlite/package.json +++ b/packages/db-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-sqlite", - "version": "3.69.0", + "version": "3.70.0", "description": "The officially supported SQLite database adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/db-vercel-postgres/package.json b/packages/db-vercel-postgres/package.json index 32fb9c1139b..a0464a8de76 100644 --- a/packages/db-vercel-postgres/package.json +++ b/packages/db-vercel-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/db-vercel-postgres", - "version": "3.69.0", + "version": "3.70.0", "description": "Vercel Postgres adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/drizzle/package.json b/packages/drizzle/package.json index 2519e481b68..3c11281bd5f 100644 --- a/packages/drizzle/package.json +++ b/packages/drizzle/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/drizzle", - "version": "3.69.0", + "version": "3.70.0", "description": "A library of shared functions used by different payload database adapters", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-nodemailer/package.json b/packages/email-nodemailer/package.json index c16a6fcf584..68d04d0a1b1 100644 --- a/packages/email-nodemailer/package.json +++ b/packages/email-nodemailer/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-nodemailer", - "version": "3.69.0", + "version": "3.70.0", "description": "Payload Nodemailer Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/email-resend/package.json b/packages/email-resend/package.json index a15b5cf7cb6..7613ddf0406 100644 --- a/packages/email-resend/package.json +++ b/packages/email-resend/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/email-resend", - "version": "3.69.0", + "version": "3.70.0", "description": "Payload Resend Email Adapter", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/graphql/package.json b/packages/graphql/package.json index b2ec5b06332..3a95651f36f 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/graphql", - "version": "3.69.0", + "version": "3.70.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/kv-redis/package.json b/packages/kv-redis/package.json index 8c452544dd1..f6ac2655454 100644 --- a/packages/kv-redis/package.json +++ b/packages/kv-redis/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/kv-redis", - "version": "3.69.0", + "version": "3.70.0", "description": "Redis KV adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-react/package.json b/packages/live-preview-react/package.json index 540e99a2b1a..c05f919a58a 100644 --- a/packages/live-preview-react/package.json +++ b/packages/live-preview-react/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-react", - "version": "3.69.0", + "version": "3.70.0", "description": "The official React SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview-vue/package.json b/packages/live-preview-vue/package.json index a69aae56914..2f7c7e2e049 100644 --- a/packages/live-preview-vue/package.json +++ b/packages/live-preview-vue/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview-vue", - "version": "3.69.0", + "version": "3.70.0", "description": "The official Vue SDK for Payload Live Preview", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/live-preview/package.json b/packages/live-preview/package.json index eba6fe3e8c2..c0f42d67be2 100644 --- a/packages/live-preview/package.json +++ b/packages/live-preview/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/live-preview", - "version": "3.69.0", + "version": "3.70.0", "description": "The official live preview JavaScript SDK for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/next/package.json b/packages/next/package.json index 9b5ccdabf00..06aa9bdfb9c 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/next", - "version": "3.69.0", + "version": "3.70.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/payload-cloud/package.json b/packages/payload-cloud/package.json index fe6a9f8f6fb..dfcf4f4d5a7 100644 --- a/packages/payload-cloud/package.json +++ b/packages/payload-cloud/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/payload-cloud", - "version": "3.69.0", + "version": "3.70.0", "description": "The official Payload Cloud plugin", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/payload/package.json b/packages/payload/package.json index 36759436695..c096d10f9d4 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "3.69.0", + "version": "3.70.0", "description": "Node, React, Headless CMS and Application Framework built on Next.js", "keywords": [ "admin panel", diff --git a/packages/plugin-cloud-storage/package.json b/packages/plugin-cloud-storage/package.json index c52fe23ebe3..e1764ead454 100644 --- a/packages/plugin-cloud-storage/package.json +++ b/packages/plugin-cloud-storage/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-cloud-storage", - "version": "3.69.0", + "version": "3.70.0", "description": "The official cloud storage plugin for Payload CMS", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-ecommerce/package.json b/packages/plugin-ecommerce/package.json index 026bcd32bea..46e3bb9e30d 100644 --- a/packages/plugin-ecommerce/package.json +++ b/packages/plugin-ecommerce/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-ecommerce", - "version": "3.69.0", + "version": "3.70.0", "description": "Ecommerce plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-form-builder/package.json b/packages/plugin-form-builder/package.json index e42e26ebad5..22da850eda9 100644 --- a/packages/plugin-form-builder/package.json +++ b/packages/plugin-form-builder/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-form-builder", - "version": "3.69.0", + "version": "3.70.0", "description": "Form builder plugin for Payload CMS", "keywords": [ "payload", diff --git a/packages/plugin-import-export/package.json b/packages/plugin-import-export/package.json index 94d19ad7fdd..89e3f03bd05 100644 --- a/packages/plugin-import-export/package.json +++ b/packages/plugin-import-export/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-import-export", - "version": "3.69.0", + "version": "3.70.0", "description": "Import-Export plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-mcp/package.json b/packages/plugin-mcp/package.json index f9181038e2a..e306efbc4dd 100644 --- a/packages/plugin-mcp/package.json +++ b/packages/plugin-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-mcp", - "version": "3.69.0", + "version": "3.70.0", "description": "MCP (Model Context Protocol) capabilities with Payload", "keywords": [ "plugin", diff --git a/packages/plugin-multi-tenant/package.json b/packages/plugin-multi-tenant/package.json index adaa951ecaa..b7616860d70 100644 --- a/packages/plugin-multi-tenant/package.json +++ b/packages/plugin-multi-tenant/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-multi-tenant", - "version": "3.69.0", + "version": "3.70.0", "description": "Multi Tenant plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-nested-docs/package.json b/packages/plugin-nested-docs/package.json index b32afde31be..0f23da10262 100644 --- a/packages/plugin-nested-docs/package.json +++ b/packages/plugin-nested-docs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-nested-docs", - "version": "3.69.0", + "version": "3.70.0", "description": "The official Nested Docs plugin for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/plugin-redirects/package.json b/packages/plugin-redirects/package.json index 6f8c74582f0..a8931729d6a 100644 --- a/packages/plugin-redirects/package.json +++ b/packages/plugin-redirects/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-redirects", - "version": "3.69.0", + "version": "3.70.0", "description": "Redirects plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-search/package.json b/packages/plugin-search/package.json index 79a510b1da3..82f67e8e018 100644 --- a/packages/plugin-search/package.json +++ b/packages/plugin-search/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-search", - "version": "3.69.0", + "version": "3.70.0", "description": "Search plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-sentry/package.json b/packages/plugin-sentry/package.json index 00ccf2b5fa6..d9cd4b55cba 100644 --- a/packages/plugin-sentry/package.json +++ b/packages/plugin-sentry/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-sentry", - "version": "3.69.0", + "version": "3.70.0", "description": "Sentry plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-seo/package.json b/packages/plugin-seo/package.json index 7b00eb210b6..5b130e71d2c 100644 --- a/packages/plugin-seo/package.json +++ b/packages/plugin-seo/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-seo", - "version": "3.69.0", + "version": "3.70.0", "description": "SEO plugin for Payload", "keywords": [ "payload", diff --git a/packages/plugin-stripe/package.json b/packages/plugin-stripe/package.json index 0b84083528c..717625102bc 100644 --- a/packages/plugin-stripe/package.json +++ b/packages/plugin-stripe/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/plugin-stripe", - "version": "3.69.0", + "version": "3.70.0", "description": "Stripe plugin for Payload", "keywords": [ "payload", diff --git a/packages/richtext-lexical/package.json b/packages/richtext-lexical/package.json index 090db524e1b..8d9d4e3420c 100644 --- a/packages/richtext-lexical/package.json +++ b/packages/richtext-lexical/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-lexical", - "version": "3.69.0", + "version": "3.70.0", "description": "The officially supported Lexical richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/richtext-slate/package.json b/packages/richtext-slate/package.json index 52e833e093e..5cb0e7879bf 100644 --- a/packages/richtext-slate/package.json +++ b/packages/richtext-slate/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/richtext-slate", - "version": "3.69.0", + "version": "3.70.0", "description": "The officially supported Slate richtext adapter for Payload", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index afb834ac638..4af973bbf71 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/sdk", - "version": "3.69.0", + "version": "3.70.0", "description": "The official Payload REST API SDK", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-azure/package.json b/packages/storage-azure/package.json index aebacda135f..d1397565fa3 100644 --- a/packages/storage-azure/package.json +++ b/packages/storage-azure/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-azure", - "version": "3.69.0", + "version": "3.70.0", "description": "Payload storage adapter for Azure Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-gcs/package.json b/packages/storage-gcs/package.json index e132519e583..97444ff38ae 100644 --- a/packages/storage-gcs/package.json +++ b/packages/storage-gcs/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-gcs", - "version": "3.69.0", + "version": "3.70.0", "description": "Payload storage adapter for Google Cloud Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-r2/package.json b/packages/storage-r2/package.json index 7411b439d55..8bd3b2ef7aa 100644 --- a/packages/storage-r2/package.json +++ b/packages/storage-r2/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-r2", - "version": "3.69.0", + "version": "3.70.0", "description": "Payload storage adapter for Cloudflare R2", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-s3/package.json b/packages/storage-s3/package.json index a8d35f29830..0b4368d4ddd 100644 --- a/packages/storage-s3/package.json +++ b/packages/storage-s3/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-s3", - "version": "3.69.0", + "version": "3.70.0", "description": "Payload storage adapter for Amazon S3", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-uploadthing/package.json b/packages/storage-uploadthing/package.json index 88d583c58cf..a6878b03504 100644 --- a/packages/storage-uploadthing/package.json +++ b/packages/storage-uploadthing/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-uploadthing", - "version": "3.69.0", + "version": "3.70.0", "description": "Payload storage adapter for uploadthing", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/storage-vercel-blob/package.json b/packages/storage-vercel-blob/package.json index 48d7f235601..a0cc6829258 100644 --- a/packages/storage-vercel-blob/package.json +++ b/packages/storage-vercel-blob/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/storage-vercel-blob", - "version": "3.69.0", + "version": "3.70.0", "description": "Payload storage adapter for Vercel Blob Storage", "homepage": "https://payloadcms.com", "repository": { diff --git a/packages/translations/package.json b/packages/translations/package.json index 2f35c58c42e..5d48b2cce8f 100644 --- a/packages/translations/package.json +++ b/packages/translations/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/translations", - "version": "3.69.0", + "version": "3.70.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", diff --git a/packages/ui/package.json b/packages/ui/package.json index 9c402e9c47e..38af3174e24 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/ui", - "version": "3.69.0", + "version": "3.70.0", "homepage": "https://payloadcms.com", "repository": { "type": "git", From da39e3e26434384b2237cda7d12b1ff227eb9978 Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Mon, 5 Jan 2026 15:38:50 -0500 Subject: [PATCH 55/67] templates: bump for v3.70.0 (#15090) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Automated bump of templates for v3.70.0 Triggered by user: @denolfe Co-authored-by: github-actions[bot] --- templates/with-cloudflare-d1/package.json | 12 ++++---- templates/with-postgres/package.json | 10 +++---- ...tial.json => 20260105_201519_initial.json} | 2 +- ..._initial.ts => 20260105_201519_initial.ts} | 0 .../with-postgres/src/migrations/index.ts | 8 +++--- templates/with-vercel-mongodb/package.json | 14 +++++----- templates/with-vercel-postgres/package.json | 14 +++++----- ...tial.json => 20260105_201440_initial.json} | 2 +- ..._initial.ts => 20260105_201440_initial.ts} | 0 .../src/migrations/index.ts | 8 +++--- templates/with-vercel-website/package.json | 28 +++++++++---------- .../src/components/Media/ImageMedia/index.tsx | 28 +++++++++++++++++++ ...tial.json => 20260105_201500_initial.json} | 2 +- ..._initial.ts => 20260105_201500_initial.ts} | 0 .../src/migrations/index.ts | 8 +++--- 15 files changed, 82 insertions(+), 54 deletions(-) rename templates/with-postgres/src/migrations/{20251219_215121_initial.json => 20260105_201519_initial.json} (99%) rename templates/with-postgres/src/migrations/{20251219_215121_initial.ts => 20260105_201519_initial.ts} (100%) rename templates/with-vercel-postgres/src/migrations/{20251219_215042_initial.json => 20260105_201440_initial.json} (99%) rename templates/with-vercel-postgres/src/migrations/{20251219_215042_initial.ts => 20260105_201440_initial.ts} (100%) rename templates/with-vercel-website/src/migrations/{20251219_215102_initial.json => 20260105_201500_initial.json} (99%) rename templates/with-vercel-website/src/migrations/{20251219_215102_initial.ts => 20260105_201500_initial.ts} (100%) diff --git a/templates/with-cloudflare-d1/package.json b/templates/with-cloudflare-d1/package.json index bd22efafac6..22224d49269 100644 --- a/templates/with-cloudflare-d1/package.json +++ b/templates/with-cloudflare-d1/package.json @@ -26,16 +26,16 @@ }, "dependencies": { "@opennextjs/cloudflare": "^1.11.0", - "@payloadcms/db-d1-sqlite": "3.69.0", - "@payloadcms/next": "3.69.0", - "@payloadcms/richtext-lexical": "3.69.0", - "@payloadcms/storage-r2": "3.69.0", - "@payloadcms/ui": "3.69.0", + "@payloadcms/db-d1-sqlite": "3.70.0", + "@payloadcms/next": "3.70.0", + "@payloadcms/richtext-lexical": "3.70.0", + "@payloadcms/storage-r2": "3.70.0", + "@payloadcms/ui": "3.70.0", "cross-env": "^7.0.3", "dotenv": "16.4.7", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.69.0", + "payload": "3.70.0", "react": "19.2.1", "react-dom": "19.2.1" }, diff --git a/templates/with-postgres/package.json b/templates/with-postgres/package.json index f16b5506207..b44fdc1f30f 100644 --- a/templates/with-postgres/package.json +++ b/templates/with-postgres/package.json @@ -19,14 +19,14 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/db-postgres": "3.69.0", - "@payloadcms/next": "3.69.0", - "@payloadcms/richtext-lexical": "3.69.0", - "@payloadcms/ui": "3.69.0", + "@payloadcms/db-postgres": "3.70.0", + "@payloadcms/next": "3.70.0", + "@payloadcms/richtext-lexical": "3.70.0", + "@payloadcms/ui": "3.70.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.69.0", + "payload": "3.70.0", "react": "19.2.1", "react-dom": "19.2.1", "sharp": "0.34.2" diff --git a/templates/with-postgres/src/migrations/20251219_215121_initial.json b/templates/with-postgres/src/migrations/20260105_201519_initial.json similarity index 99% rename from templates/with-postgres/src/migrations/20251219_215121_initial.json rename to templates/with-postgres/src/migrations/20260105_201519_initial.json index e24bf9d8964..78cc7645d6b 100644 --- a/templates/with-postgres/src/migrations/20251219_215121_initial.json +++ b/templates/with-postgres/src/migrations/20260105_201519_initial.json @@ -934,6 +934,6 @@ "tables": {}, "columns": {} }, - "id": "467e8bdd-a159-49fd-850e-ba395659b979", + "id": "80c5ff21-e670-49dd-8c0a-1a2460fb4fce", "prevId": "00000000-0000-0000-0000-000000000000" } diff --git a/templates/with-postgres/src/migrations/20251219_215121_initial.ts b/templates/with-postgres/src/migrations/20260105_201519_initial.ts similarity index 100% rename from templates/with-postgres/src/migrations/20251219_215121_initial.ts rename to templates/with-postgres/src/migrations/20260105_201519_initial.ts diff --git a/templates/with-postgres/src/migrations/index.ts b/templates/with-postgres/src/migrations/index.ts index 53cc3e79199..2da156d45d5 100644 --- a/templates/with-postgres/src/migrations/index.ts +++ b/templates/with-postgres/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20251219_215121_initial from './20251219_215121_initial' +import * as migration_20260105_201519_initial from './20260105_201519_initial' export const migrations = [ { - up: migration_20251219_215121_initial.up, - down: migration_20251219_215121_initial.down, - name: '20251219_215121_initial', + up: migration_20260105_201519_initial.up, + down: migration_20260105_201519_initial.down, + name: '20260105_201519_initial', }, ] diff --git a/templates/with-vercel-mongodb/package.json b/templates/with-vercel-mongodb/package.json index c65ec14c36a..6b79cd01767 100644 --- a/templates/with-vercel-mongodb/package.json +++ b/templates/with-vercel-mongodb/package.json @@ -18,15 +18,15 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/db-mongodb": "3.69.0", - "@payloadcms/next": "3.69.0", - "@payloadcms/richtext-lexical": "3.69.0", - "@payloadcms/storage-vercel-blob": "3.69.0", - "@payloadcms/ui": "3.69.0", + "@payloadcms/db-mongodb": "3.70.0", + "@payloadcms/next": "3.70.0", + "@payloadcms/richtext-lexical": "3.70.0", + "@payloadcms/storage-vercel-blob": "3.70.0", + "@payloadcms/ui": "3.70.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.69.0", + "payload": "3.70.0", "react": "19.2.1", "react-dom": "19.2.1" }, @@ -48,7 +48,7 @@ "vite-tsconfig-paths": "5.1.4", "vitest": "3.2.3" }, - "packageManager": "pnpm@10.26.1", + "packageManager": "pnpm@10.27.0", "engines": { "node": "^18.20.2 || >=20.9.0" }, diff --git a/templates/with-vercel-postgres/package.json b/templates/with-vercel-postgres/package.json index f2cfc16dc92..dcd95b85539 100644 --- a/templates/with-vercel-postgres/package.json +++ b/templates/with-vercel-postgres/package.json @@ -19,15 +19,15 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/db-vercel-postgres": "3.69.0", - "@payloadcms/next": "3.69.0", - "@payloadcms/richtext-lexical": "3.69.0", - "@payloadcms/storage-vercel-blob": "3.69.0", - "@payloadcms/ui": "3.69.0", + "@payloadcms/db-vercel-postgres": "3.70.0", + "@payloadcms/next": "3.70.0", + "@payloadcms/richtext-lexical": "3.70.0", + "@payloadcms/storage-vercel-blob": "3.70.0", + "@payloadcms/ui": "3.70.0", "cross-env": "^7.0.3", "graphql": "^16.8.1", "next": "15.4.10", - "payload": "3.69.0", + "payload": "3.70.0", "react": "19.2.1", "react-dom": "19.2.1" }, @@ -49,7 +49,7 @@ "vite-tsconfig-paths": "5.1.4", "vitest": "3.2.3" }, - "packageManager": "pnpm@10.26.1", + "packageManager": "pnpm@10.27.0", "engines": { "node": "^18.20.2 || >=20.9.0" }, diff --git a/templates/with-vercel-postgres/src/migrations/20251219_215042_initial.json b/templates/with-vercel-postgres/src/migrations/20260105_201440_initial.json similarity index 99% rename from templates/with-vercel-postgres/src/migrations/20251219_215042_initial.json rename to templates/with-vercel-postgres/src/migrations/20260105_201440_initial.json index 52631e9b98a..6243115e736 100644 --- a/templates/with-vercel-postgres/src/migrations/20251219_215042_initial.json +++ b/templates/with-vercel-postgres/src/migrations/20260105_201440_initial.json @@ -934,6 +934,6 @@ "tables": {}, "columns": {} }, - "id": "a58a4163-b21a-4c60-8a8e-cc9aa119df75", + "id": "cb5b8614-fc45-42f5-874f-4c28a2401bcc", "prevId": "00000000-0000-0000-0000-000000000000" } diff --git a/templates/with-vercel-postgres/src/migrations/20251219_215042_initial.ts b/templates/with-vercel-postgres/src/migrations/20260105_201440_initial.ts similarity index 100% rename from templates/with-vercel-postgres/src/migrations/20251219_215042_initial.ts rename to templates/with-vercel-postgres/src/migrations/20260105_201440_initial.ts diff --git a/templates/with-vercel-postgres/src/migrations/index.ts b/templates/with-vercel-postgres/src/migrations/index.ts index e747e61a406..9b251bebff8 100644 --- a/templates/with-vercel-postgres/src/migrations/index.ts +++ b/templates/with-vercel-postgres/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20251219_215042_initial from './20251219_215042_initial' +import * as migration_20260105_201440_initial from './20260105_201440_initial' export const migrations = [ { - up: migration_20251219_215042_initial.up, - down: migration_20251219_215042_initial.down, - name: '20251219_215042_initial', + up: migration_20260105_201440_initial.up, + down: migration_20260105_201440_initial.down, + name: '20260105_201440_initial', }, ] diff --git a/templates/with-vercel-website/package.json b/templates/with-vercel-website/package.json index 3aded08005b..9faf827e640 100644 --- a/templates/with-vercel-website/package.json +++ b/templates/with-vercel-website/package.json @@ -23,18 +23,18 @@ "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" }, "dependencies": { - "@payloadcms/admin-bar": "3.69.0", - "@payloadcms/db-vercel-postgres": "3.69.0", - "@payloadcms/live-preview-react": "3.69.0", - "@payloadcms/next": "3.69.0", - "@payloadcms/plugin-form-builder": "3.69.0", - "@payloadcms/plugin-nested-docs": "3.69.0", - "@payloadcms/plugin-redirects": "3.69.0", - "@payloadcms/plugin-search": "3.69.0", - "@payloadcms/plugin-seo": "3.69.0", - "@payloadcms/richtext-lexical": "3.69.0", - "@payloadcms/storage-vercel-blob": "3.69.0", - "@payloadcms/ui": "3.69.0", + "@payloadcms/admin-bar": "3.70.0", + "@payloadcms/db-vercel-postgres": "3.70.0", + "@payloadcms/live-preview-react": "3.70.0", + "@payloadcms/next": "3.70.0", + "@payloadcms/plugin-form-builder": "3.70.0", + "@payloadcms/plugin-nested-docs": "3.70.0", + "@payloadcms/plugin-redirects": "3.70.0", + "@payloadcms/plugin-search": "3.70.0", + "@payloadcms/plugin-seo": "3.70.0", + "@payloadcms/richtext-lexical": "3.70.0", + "@payloadcms/storage-vercel-blob": "3.70.0", + "@payloadcms/ui": "3.70.0", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-select": "^2.0.0", @@ -48,7 +48,7 @@ "lucide-react": "^0.378.0", "next": "15.4.10", "next-sitemap": "^4.2.3", - "payload": "3.69.0", + "payload": "3.70.0", "prism-react-renderer": "^2.3.1", "react": "19.2.1", "react-dom": "19.2.1", @@ -81,7 +81,7 @@ "vite-tsconfig-paths": "5.1.4", "vitest": "3.2.3" }, - "packageManager": "pnpm@10.26.1", + "packageManager": "pnpm@10.27.0", "engines": { "node": "^18.20.2 || >=20.9.0" }, diff --git a/templates/with-vercel-website/src/components/Media/ImageMedia/index.tsx b/templates/with-vercel-website/src/components/Media/ImageMedia/index.tsx index 8a1dc106471..0caf826e72f 100644 --- a/templates/with-vercel-website/src/components/Media/ImageMedia/index.tsx +++ b/templates/with-vercel-website/src/components/Media/ImageMedia/index.tsx @@ -17,6 +17,34 @@ const { breakpoints } = cssVariables const placeholderBlur = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABchJREFUWEdtlwtTG0kMhHtGM7N+AAdcDsjj///EBLzenbtuadbLJaZUTlHB+tRqSesETB3IABqQG1KbUFqDlQorBSmboqeEBcC1d8zrCixXYGZcgMsFmH8B+AngHdurAmXKOE8nHOoBrU6opcGswPi5KSP9CcBaQ9kACJH/ALAA1xm4zMD8AczvQCcAQeJVAZsy7nYApTSUzwCHUKACeUJi9TsFci7AHmDtuHYqQIC9AgQYKnSwNAig4NyOOwXq/xU47gDYggarjIpsRSEA3Fqw7AGkwgW4fgALAdiC2btKgNZwbgdMbEFpqFR2UyCR8xwAhf8bUHIGk1ckMyB5C1YkeWAdAPQBAeiD6wVYPoD1HUgXwFagZAGc6oSpTmilopoD5GzISQD3odcNIFca0BUQQM5YA2DpHV0AYURBDIAL0C+ugC0C4GedSsVUmwC8/4w8TPiwU6AClJ5RWL1PgQNkrABWdKB3YF3cBwRY5lsI4ApkKpCQi+FIgFJU/TDgDuAxAAwonJuKpGD1rkCXCR1ALyrAUSSEQAhwBdYZ6DPAgSUA2c1wKIZmRcHxMzMYR9DH8NlbkAwwApSAcABwBwTAbb6owAr0AFiZPILVEyCtMmK2jCkTwFDNUNj7nJETQx744gCUmgkZVGJUHyakEZE4W91jtGFA9KsD8Z3JFYDlhGYZLWcllwJMnplcPy+csFAgAAaIDOgeuAGoB96GLZg4kmtfMjnr6ig5oSoySsoy3ya/FMivXZWxwr0KIf9nACbfqcBEgmBSAtAlIT83R+70IWpyACamIjf5E1Iqb9ECVmnoI/FvAIRk8s2J0Y5IquQDgB+5wpScw5AUTC75VTmTs+72NUzoCvQIaAXv5Q8PDAZKLD+MxLv3RFE7KlsQChgBIlKiCv5ByaZv3gJZNm8AnVMhAN+EjrtTYQMICJpu6/0aiQnhClANlz+Bw0cIWa8ev0sBrtrhAyaXEnrfGfATQJiRKih5vKeOHNXXPFrgyamAADh0Q4F2/sESojomDS9o9k0b0H83xjB8qL+JNoTjN+enjpaBpingRh4e8MSugudM030A8FeqMI6PFIgNyPehkpZWGFEAARIQdH5LcAAqIACHkAJqg4OoBccHAuz76wr4BbzFOEa8iBuAZB8AtJHLP2VgMgJw/EIBowo7HxCAH3V6dAXEE/vZ5aZIA8BP8RKhm7Cp8BnAMnAQADdgQDA520AVIpScP+enHz0Gwp25h4i2dPg5FkDXrbsdJikQwXuWgaM5gEMk1AgH4DKKFjDf3bMD+FjEeIxLlRKYnBk2BbquvSDCAQ4gwZiMAAmH4gBTyRtEsYxi7gP6QSrc//39BrDNqG8rtYTmC4BV1SfMhOhaumFCT87zy4pPhQBZEK1kQVRjJBBi7AOlePgyAPYjwlvtagx9e/dnQraAyS894TIkkAIEYMKEc8k4EqJ68lZ5jjNqcQC2QteQOf7659umwBgPybNtK4dg9WvnMyFwXYGP7uEO1lwJgAnPNeMYMVXbIIYKFioI4PGFt+BWPVfmWJdjW2lTUnLGCswECAgaUy86iwA1464ajo0QhgMBFGyBoZahANsMpMfXr1JA1SN29m5lqgXj+UPV85uRA7yv/KYUO4Tk7Hc1AZwbIRzg0AyNj2UlAMwfSLSMnl7fdAbcxHuA27YaAMvaQ4GOjwX4RTUGAG8Ge14N963g1AynqUiFqRX9noasxT4b8entNRQYyamk/3tYcHsO7R3XJRRYOn4tw4iUnwBM5gDnySGOreAwAGo8F9IDHEcq8Pz2Kg/oXCpuIL6tOPD8LsDn0ABYQoGFRowlsAEUPPDrGAGowAbgKsgDMmE8mDy/vXQ9IAwI7u4wta+gAdAdgB64Ah9SgD4IgGKhwACoAjgNgFDhtxY8f33ZTMjqdTAiHMBPrn8ZWkEfzFdX4Oc1AHg3+ADbvN8PU8WdFKg4Tt6CQy2+D4YHaMT/JP4XzbAq98cPDIUAAAAASUVORK5CYII=' +/** + * ImageMedia + * + * This component passes a **relative** `src` (e.g. `/media/...`) to Next.js Image. + * The `getMediaUrl` utility constructs the full URL by prepending the base URL from env vars + * (NEXT_PUBLIC_SERVER_URL). Next.js then optimizes this using `remotePatterns` configured + * in next.config.js — no custom `loader` needed. + * + * Flow: + * 1. Resource URL from Payload: `/media/image-123.jpg` + * 2. getMediaUrl() adds base URL: `https://yourdomain.com/media/image-123.jpg` + * 3. Next.js Image optimizes via remotePatterns: `/_next/image?url=...&w=1200&q=75` + * + * If your storage/plugin returns **external CDN URLs** (e.g. `https://cdn.example.com/...`), + * choose ONE of the following: + * A) Allow the remote host in next.config.js: + * images: { remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }] } + * B) Provide a **custom loader** for CDN-specific transforms: + * const imageLoader: ImageLoader = ({ src, width, quality }) => + * `https://cdn.example.com${src}?w=${width}&q=${quality ?? 75}` + * + * C) Skip optimization: + * + * + * TL;DR: Template uses relative URLs + getMediaUrl() to construct full URLs, then relies on + * remotePatterns for optimization. Only add `loader` if using external CDNs with custom transforms. + */ + export const ImageMedia: React.FC = (props) => { const { alt: altFromProps, diff --git a/templates/with-vercel-website/src/migrations/20251219_215102_initial.json b/templates/with-vercel-website/src/migrations/20260105_201500_initial.json similarity index 99% rename from templates/with-vercel-website/src/migrations/20251219_215102_initial.json rename to templates/with-vercel-website/src/migrations/20260105_201500_initial.json index d68bf187faa..197d6168c28 100644 --- a/templates/with-vercel-website/src/migrations/20251219_215102_initial.json +++ b/templates/with-vercel-website/src/migrations/20260105_201500_initial.json @@ -9181,6 +9181,6 @@ "tables": {}, "columns": {} }, - "id": "6b0e67eb-144f-4853-8c3e-309797d35a20", + "id": "0c79da22-ff42-4988-87da-0f8495063d0a", "prevId": "00000000-0000-0000-0000-000000000000" } diff --git a/templates/with-vercel-website/src/migrations/20251219_215102_initial.ts b/templates/with-vercel-website/src/migrations/20260105_201500_initial.ts similarity index 100% rename from templates/with-vercel-website/src/migrations/20251219_215102_initial.ts rename to templates/with-vercel-website/src/migrations/20260105_201500_initial.ts diff --git a/templates/with-vercel-website/src/migrations/index.ts b/templates/with-vercel-website/src/migrations/index.ts index 8488648ffba..47d9e4e89b8 100644 --- a/templates/with-vercel-website/src/migrations/index.ts +++ b/templates/with-vercel-website/src/migrations/index.ts @@ -1,9 +1,9 @@ -import * as migration_20251219_215102_initial from './20251219_215102_initial' +import * as migration_20260105_201500_initial from './20260105_201500_initial' export const migrations = [ { - up: migration_20251219_215102_initial.up, - down: migration_20251219_215102_initial.down, - name: '20251219_215102_initial', + up: migration_20260105_201500_initial.up, + down: migration_20260105_201500_initial.down, + name: '20260105_201500_initial', }, ] From a9909ac8fe112889a0281085a43e880349a248b5 Mon Sep 17 00:00:00 2001 From: Thomas Coldwell <31568400+thomas-coldwell@users.noreply.github.com> Date: Tue, 6 Jan 2026 18:13:36 +0000 Subject: [PATCH 56/67] feat: add typescript.strictDraftTypes flag for opt-in draft query type safety (#14388) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What? This PR adds an opt-in `typescript.strictDraftTypes` config flag that enables strict type safety for draft mode queries. When enabled, `find` operations with `draft: true` will correctly type required fields as optional. ```typescript export default buildConfig({ typescript: { strictDraftTypes: true, // <-- defaults to false }, // ... }) ``` ### Why? Support for correct types when creating a draft document was added in #14271, however, the types returned when querying a document (e.g. via Local API `find`) with `draft: true` still return incorrect types—many required fields are possibly null but typed as non-null. Making this change without a flag would be a breaking change for existing user code, as any queries using a dynamic `draft` parameter would start showing required fields as optional, requiring null checks throughout their codebase. By introducing this behind a flag, users can opt-in when ready, and it will become the default behavior in v4.0. ### How? - Added `strictDraftTypes` config flag to `typescript` config object (defaults to `false`) - Added a generic `TDraft extends boolean` parameter to `find()` and `findLocal()` - Added conditional return types that check both `TDraft` and `GeneratedTypes extends { strictDraftTypes: true }` - Created `QueryDraftDataFromCollection` type for draft query results where: - `id` is required (always present in query results) - User-defined required fields are optional (validation skipped for drafts) - System fields like `createdAt`, `updatedAt` are optional - Updated `DraftTransformCollectionWithSelect` to use the new type for draft queries - Modified type generation to add `strictDraftTypes: true` to `GeneratedTypes` when enabled --------- Co-authored-by: Patrik Kozak <35232443+PatrikKozak@users.noreply.github.com> --- docs/configuration/overview.mdx | 11 ++-- .../payload/src/collections/config/types.ts | 21 ++++++- .../src/collections/operations/local/find.ts | 15 ++++- packages/payload/src/config/types.ts | 8 +++ packages/payload/src/index.ts | 21 +++++-- packages/payload/src/types/index.ts | 8 +++ .../src/utilities/configToJSONSchema.ts | 9 +++ test/types/config.ts | 19 ++++++ test/types/payload-types.ts | 62 ++++++++++++++++++- test/types/types.spec.ts | 37 +++++++++++ 10 files changed, 195 insertions(+), 16 deletions(-) diff --git a/docs/configuration/overview.mdx b/docs/configuration/overview.mdx index f08f428b45a..1338624c554 100644 --- a/docs/configuration/overview.mdx +++ b/docs/configuration/overview.mdx @@ -131,11 +131,12 @@ export default buildConfig({ The following options are available: -| Option | Description | -| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`autoGenerate`** | By default, Payload will auto-generate TypeScript interfaces for all collections and globals that your config defines. Opt out by setting `typescript.autoGenerate: false`. [More details](../typescript/overview). | -| **`declare`** | By default, Payload adds a `declare` block to your generated types, which makes sure that Payload uses your generated types for all Local API methods. Opt out by setting `typescript.declare: false`. | -| **`outputFile`** | Control the output path and filename of Payload's auto-generated types by defining the `typescript.outputFile` property to a full, absolute path. | +| Option | Description | +| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`autoGenerate`** | By default, Payload will auto-generate TypeScript interfaces for all collections and globals that your config defines. Opt out by setting `typescript.autoGenerate: false`. [More details](../typescript/overview). | +| **`declare`** | By default, Payload adds a `declare` block to your generated types, which makes sure that Payload uses your generated types for all Local API methods. Opt out by setting `typescript.declare: false`. | +| **`outputFile`** | Control the output path and filename of Payload's auto-generated types by defining the `typescript.outputFile` property to a full, absolute path. | +| **`strictDraftTypes`** | Enable strict type safety for draft mode queries. When enabled, `find` operations with `draft: true` will type required fields as optional, since validation is skipped for drafts. Defaults to `false`. **This will become the default behavior in v4.0.** | ## Config Location diff --git a/packages/payload/src/collections/config/types.ts b/packages/payload/src/collections/config/types.ts index 41af41882e2..37468240c87 100644 --- a/packages/payload/src/collections/config/types.ts +++ b/packages/payload/src/collections/config/types.ts @@ -80,17 +80,32 @@ export type RequiredDataFromCollectionSlug = RequiredDataFromCollection> /** - * Helper type for draft data - makes all fields optional except auto-generated ones + * Helper type for draft data INPUT (e.g., create operations) - makes all fields optional except system fields * When creating a draft, required fields don't need to be provided as validation is skipped + * The id field is optional since it's auto-generated */ export type DraftDataFromCollection = Partial< - MarkOptional -> + Omit +> & + Partial> export type DraftDataFromCollectionSlug = DraftDataFromCollection< DataFromCollectionSlug > +/** + * Helper type for draft data OUTPUT (e.g., query results) - makes user fields optional but keeps id required + * When querying drafts, required fields may be null/undefined as validation is skipped, but system fields like id are always present + */ +export type QueryDraftDataFromCollection = Partial< + Omit +> & + Partial> & + Pick + +export type QueryDraftDataFromCollectionSlug = + QueryDraftDataFromCollection> + export type HookOperationType = | 'autosave' | 'count' diff --git a/packages/payload/src/collections/operations/local/find.ts b/packages/payload/src/collections/operations/local/find.ts index 849d06c820b..72914a3f598 100644 --- a/packages/payload/src/collections/operations/local/find.ts +++ b/packages/payload/src/collections/operations/local/find.ts @@ -1,6 +1,7 @@ import type { PaginatedDocs } from '../../../database/types.js' import type { CollectionSlug, + GeneratedTypes, JoinQuery, Payload, RequestContext, @@ -9,6 +10,7 @@ import type { } from '../../../index.js' import type { Document, + DraftTransformCollectionWithSelect, PayloadRequest, PopulateType, SelectType, @@ -137,10 +139,19 @@ export type Options = export async function findLocal< TSlug extends CollectionSlug, TSelect extends SelectFromCollectionSlug, + TDraft extends boolean = false, >( payload: Payload, - options: Options, -): Promise>> { + options: { draft?: TDraft } & Options, +): Promise< + PaginatedDocs< + TDraft extends true + ? GeneratedTypes extends { strictDraftTypes: true } + ? DraftTransformCollectionWithSelect + : TransformCollectionWithSelect + : TransformCollectionWithSelect + > +> { const { collection: collectionSlug, currentDepth, diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index 5941e5090fd..9f4c606e21f 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -1398,6 +1398,14 @@ export type Config = { jsonSchema: JSONSchema4 }) => JSONSchema4 > + + /** + * Enable strict type safety for draft mode queries. + * When enabled, find operations with draft: true will type required fields as optional. + * @default false + * @todo Remove in v4. Strict draft types will become the default behavior. + */ + strictDraftTypes?: boolean } /** * Customize the handling of incoming file uploads for collections that have uploads enabled. diff --git a/packages/payload/src/index.ts b/packages/payload/src/index.ts index 93af68c321c..f3b74fa6b49 100644 --- a/packages/payload/src/index.ts +++ b/packages/payload/src/index.ts @@ -45,6 +45,7 @@ import type { InitializedEmailAdapter } from './email/types.js' import type { DataFromGlobalSlug, Globals, SelectFromGlobalSlug } from './globals/config/types.js' import type { ApplyDisableErrors, + DraftTransformCollectionWithSelect, JsonObject, SelectType, TransformCollectionWithSelect, @@ -457,10 +458,22 @@ export class BasePayload { * @param options * @returns documents satisfying query */ - find = async >( - options: FindOptions, - ): Promise>> => { - return findLocal(this, options) + find = async < + TSlug extends CollectionSlug, + TSelect extends SelectFromCollectionSlug, + TDraft extends boolean = false, + >( + options: { draft?: TDraft } & FindOptions, + ): Promise< + PaginatedDocs< + TDraft extends true + ? GeneratedTypes extends { strictDraftTypes: true } + ? DraftTransformCollectionWithSelect + : TransformCollectionWithSelect + : TransformCollectionWithSelect + > + > => { + return findLocal(this, options) } /** diff --git a/packages/payload/src/types/index.ts b/packages/payload/src/types/index.ts index ead5f57351b..e3fa3cc8c92 100644 --- a/packages/payload/src/types/index.ts +++ b/packages/payload/src/types/index.ts @@ -5,6 +5,7 @@ import type { URL } from 'url' import type { DataFromCollectionSlug, + QueryDraftDataFromCollectionSlug, TypeWithID, TypeWithTimestamps, } from '../collections/config/types.js' @@ -258,6 +259,13 @@ export type TransformCollectionWithSelect< ? TransformDataWithSelect, TSelect> : DataFromCollectionSlug +export type DraftTransformCollectionWithSelect< + TSlug extends CollectionSlug, + TSelect extends SelectType, +> = TSelect extends SelectType + ? TransformDataWithSelect, TSelect> + : QueryDraftDataFromCollectionSlug + export type TransformGlobalWithSelect< TSlug extends GlobalSlug, TSelect extends SelectType, diff --git a/packages/payload/src/utilities/configToJSONSchema.ts b/packages/payload/src/utilities/configToJSONSchema.ts index db934fee155..3f9cafbccb2 100644 --- a/packages/payload/src/utilities/configToJSONSchema.ts +++ b/packages/payload/src/utilities/configToJSONSchema.ts @@ -1269,6 +1269,14 @@ export function configToJSONSchema( globals: generateEntitySchemas(config.globals || []), globalsSelect: generateEntitySelectSchemas(config.globals || []), locale: generateLocaleEntitySchemas(config.localization), + ...(config.typescript?.strictDraftTypes + ? { + strictDraftTypes: { + type: 'boolean', + const: true, + }, + } + : {}), user: generateAuthEntitySchemas(config.collections), }, required: [ @@ -1279,6 +1287,7 @@ export function configToJSONSchema( 'collectionsSelect', 'collectionsJoins', 'globalsSelect', + ...(config.typescript?.strictDraftTypes ? ['strictDraftTypes'] : []), 'globals', 'auth', 'db', diff --git a/test/types/config.ts b/test/types/config.ts index 2566b0778ef..a230824e22f 100644 --- a/test/types/config.ts +++ b/test/types/config.ts @@ -119,6 +119,24 @@ export default buildConfigWithDefaults({ }, ], }, + { + slug: 'draft-posts', + versions: { + drafts: true, + }, + fields: [ + { + type: 'text', + name: 'title', + required: true, + }, + { + type: 'text', + name: 'description', + required: true, + }, + ], + }, ], admin: { importMap: { @@ -140,5 +158,6 @@ export default buildConfigWithDefaults({ ], typescript: { outputFile: path.resolve(dirname, 'payload-types.ts'), + strictDraftTypes: true, }, }) diff --git a/test/types/payload-types.ts b/test/types/payload-types.ts index f0f1743c9bb..3b998398773 100644 --- a/test/types/payload-types.ts +++ b/test/types/payload-types.ts @@ -80,6 +80,8 @@ export interface Config { posts: Post; pages: Page; 'pages-categories': PagesCategory; + 'draft-posts': DraftPost; + 'payload-kv': PayloadKv; users: User; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -94,6 +96,8 @@ export interface Config { posts: PostsSelect | PostsSelect; pages: PagesSelect | PagesSelect; 'pages-categories': PagesCategoriesSelect | PagesCategoriesSelect; + 'draft-posts': DraftPostsSelect | DraftPostsSelect; + 'payload-kv': PayloadKvSelect | PayloadKvSelect; users: UsersSelect | UsersSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -102,6 +106,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: null; globals: { menu: Menu; }; @@ -109,6 +114,7 @@ export interface Config { menu: MenuSelect | MenuSelect; }; locale: null; + strictDraftTypes: true; user: User & { collection: 'users'; }; @@ -198,6 +204,35 @@ export interface PagesCategory { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "draft-posts". + */ +export interface DraftPost { + id: string; + title: string; + description: string; + updatedAt: string; + createdAt: string; + _status?: ('draft' | 'published') | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv". + */ +export interface PayloadKv { + id: string; + key: string; + data: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -241,6 +276,10 @@ export interface PayloadLockedDocument { relationTo: 'pages-categories'; value: string | PagesCategory; } | null) + | ({ + relationTo: 'draft-posts'; + value: string | DraftPost; + } | null) | ({ relationTo: 'users'; value: string | User; @@ -327,6 +366,25 @@ export interface PagesCategoriesSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "draft-posts_select". + */ +export interface DraftPostsSelect { + title?: T; + description?: T; + updatedAt?: T; + createdAt?: T; + _status?: T; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv_select". + */ +export interface PayloadKvSelect { + key?: T; + data?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". @@ -411,6 +469,6 @@ export interface Auth { declare module 'payload' { - // @ts-ignore + // @ts-ignore export interface GeneratedTypes extends Config {} -} +} \ No newline at end of file diff --git a/test/types/types.spec.ts b/test/types/types.spec.ts index 090d2da787f..582ed0cc09a 100644 --- a/test/types/types.spec.ts +++ b/test/types/types.spec.ts @@ -888,4 +888,41 @@ describe('Types testing', () => { }) }) }) + + describe('strictDraftTypes flag', () => { + test('draft find query returns optional required fields when flag is enabled', async () => { + const result = await payload.find({ + collection: 'draft-posts', + draft: true, + }) + + const doc = result.docs[0]! + + // With strictDraftTypes enabled, user-defined required fields should be optional in draft queries + expect(doc.description).type.toBe() + expect(doc.title).type.toBe() + + // Only id is required in draft queries - other system fields are also optional + expect(doc.id).type.not.toBe() + expect(doc.createdAt).type.toBe() + expect(doc.updatedAt).type.toBe() + }) + + test('non-draft find query returns required fields as required', async () => { + const result = await payload.find({ + collection: 'draft-posts', + }) + + const doc = result.docs[0]! + + // Without draft mode, required fields should remain required + expect(doc.description).type.toBe() + expect(doc.title).type.toBe() + + // System fields should also be present and required (not undefined) + expect(doc.id).type.not.toBe() + expect(doc.createdAt).type.toBe() + expect(doc.updatedAt).type.toBe() + }) + }) }) From 603c813721aaa4b3069a1e5e82c66f7a87eeb550 Mon Sep 17 00:00:00 2001 From: Kendell <1900724+kendelljoseph@users.noreply.github.com> Date: Tue, 6 Jan 2026 14:14:28 -0500 Subject: [PATCH 57/67] feat(plugin-mcp): adds tools that can find and update globals (#15091) Adds MCP tools that can `find` and `update` globals. --------- Co-authored-by: Steven Ceuppens Co-authored-by: Claude --- .../collections/createApiKeysCollection.ts | 122 ++----------- packages/plugin-mcp/src/index.ts | 4 + packages/plugin-mcp/src/mcp/getMcpHandler.ts | 88 ++++++--- .../plugin-mcp/src/mcp/tools/global/find.ts | 104 +++++++++++ .../plugin-mcp/src/mcp/tools/global/update.ts | 168 ++++++++++++++++++ packages/plugin-mcp/src/mcp/tools/schemas.ts | 50 ++++++ packages/plugin-mcp/src/types.ts | 60 ++++++- .../src/utils/adminEntitySettings.ts | 40 +++++ .../src/utils/createApiKeyFields.ts | 72 ++++++++ .../plugin-mcp/src/utils/getEnabledSlugs.ts | 42 +++++ test/plugin-mcp/config.ts | 11 ++ test/plugin-mcp/globals/SiteSettings.ts | 37 ++++ test/plugin-mcp/int.spec.ts | 104 ++++++++++- test/plugin-mcp/payload-types.ts | 62 ++++++- 14 files changed, 822 insertions(+), 142 deletions(-) create mode 100644 packages/plugin-mcp/src/mcp/tools/global/find.ts create mode 100644 packages/plugin-mcp/src/mcp/tools/global/update.ts create mode 100644 packages/plugin-mcp/src/utils/adminEntitySettings.ts create mode 100644 packages/plugin-mcp/src/utils/createApiKeyFields.ts create mode 100644 packages/plugin-mcp/src/utils/getEnabledSlugs.ts create mode 100644 test/plugin-mcp/globals/SiteSettings.ts diff --git a/packages/plugin-mcp/src/collections/createApiKeysCollection.ts b/packages/plugin-mcp/src/collections/createApiKeysCollection.ts index bf91907a6fa..719c2cc5675 100644 --- a/packages/plugin-mcp/src/collections/createApiKeysCollection.ts +++ b/packages/plugin-mcp/src/collections/createApiKeysCollection.ts @@ -3,119 +3,11 @@ import type { CollectionConfig } from 'payload' import type { PluginMCPServerConfig } from '../types.js' import { toCamelCase } from '../utils/camelCase.js' - -const addEnabledCollectionTools = (collections: PluginMCPServerConfig['collections']) => { - const enabledCollectionSlugs = Object.keys(collections || {}).filter((collection) => { - const fullyEnabled = - typeof collections?.[collection]?.enabled === 'boolean' && collections?.[collection]?.enabled - - if (fullyEnabled) { - return true - } - - const partiallyEnabled = - typeof collections?.[collection]?.enabled !== 'boolean' && - ((typeof collections?.[collection]?.enabled?.find === 'boolean' && - collections?.[collection]?.enabled?.find === true) || - (typeof collections?.[collection]?.enabled?.create === 'boolean' && - collections?.[collection]?.enabled?.create === true) || - (typeof collections?.[collection]?.enabled?.update === 'boolean' && - collections?.[collection]?.enabled?.update === true) || - (typeof collections?.[collection]?.enabled?.delete === 'boolean' && - collections?.[collection]?.enabled?.delete === true)) - - if (partiallyEnabled) { - return true - } - }) - return enabledCollectionSlugs.map((enabledCollectionSlug) => ({ - type: 'collapsible' as const, - admin: { - description: `Manage client access to ${enabledCollectionSlug}`, - position: 'sidebar' as const, - }, - fields: [ - { - name: `${toCamelCase(enabledCollectionSlug)}`, - type: 'group' as const, - fields: [ - ...(collections?.[enabledCollectionSlug]?.enabled === true || - (typeof collections?.[enabledCollectionSlug]?.enabled !== 'boolean' && - typeof collections?.[enabledCollectionSlug]?.enabled?.find === 'boolean' && - collections?.[enabledCollectionSlug]?.enabled?.find === true) - ? [ - { - name: `find`, - type: 'checkbox' as const, - admin: { - description: `Allow clients to find ${enabledCollectionSlug}.`, - }, - defaultValue: false, - label: 'Find', - }, - ] - : []), - - ...(collections?.[enabledCollectionSlug]?.enabled === true || - (typeof collections?.[enabledCollectionSlug]?.enabled !== 'boolean' && - typeof collections?.[enabledCollectionSlug]?.enabled?.create === 'boolean' && - collections?.[enabledCollectionSlug]?.enabled?.create === true) - ? [ - { - name: `create`, - type: 'checkbox' as const, - admin: { - description: `Allow clients to create ${enabledCollectionSlug}.`, - }, - defaultValue: false, - label: 'Create', - }, - ] - : []), - - ...(collections?.[enabledCollectionSlug]?.enabled === true || - (typeof collections?.[enabledCollectionSlug]?.enabled !== 'boolean' && - typeof collections?.[enabledCollectionSlug]?.enabled?.update === 'boolean' && - collections?.[enabledCollectionSlug]?.enabled?.update === true) - ? [ - { - name: `update`, - type: 'checkbox' as const, - admin: { - description: `Allow clients to update ${enabledCollectionSlug}.`, - }, - defaultValue: false, - label: 'Update', - }, - ] - : []), - - ...(collections?.[enabledCollectionSlug]?.enabled === true || - (typeof collections?.[enabledCollectionSlug]?.enabled !== 'boolean' && - typeof collections?.[enabledCollectionSlug]?.enabled?.delete === 'boolean' && - collections?.[enabledCollectionSlug]?.enabled?.delete === true) - ? [ - { - name: `delete`, - type: 'checkbox' as const, - admin: { - description: `Allow clients to delete ${enabledCollectionSlug}.`, - }, - defaultValue: false, - label: 'Delete', - }, - ] - : []), - ], - label: false as const, - }, - ], - label: `${enabledCollectionSlug.charAt(0).toUpperCase() + toCamelCase(enabledCollectionSlug).slice(1)}`, - })) -} +import { createApiKeyFields } from '../utils/createApiKeyFields.js' export const createAPIKeysCollection = ( collections: PluginMCPServerConfig['collections'], + globals: PluginMCPServerConfig['globals'], customTools: Array<{ description: string; name: string }> = [], experimentalTools: NonNullable['tools'] = {}, pluginOptions: PluginMCPServerConfig, @@ -204,7 +96,15 @@ export const createAPIKeysCollection = ( }, }, - ...addEnabledCollectionTools(collections), + ...createApiKeyFields({ + config: collections, + configType: 'collection', + }), + + ...createApiKeyFields({ + config: globals, + configType: 'global', + }), ...(customTools.length > 0 ? [ diff --git a/packages/plugin-mcp/src/index.ts b/packages/plugin-mcp/src/index.ts index dc1e3918446..a980deaf4e0 100644 --- a/packages/plugin-mcp/src/index.ts +++ b/packages/plugin-mcp/src/index.ts @@ -27,6 +27,8 @@ export const mcpPlugin = // Collections const collections = pluginOptions.collections || {} + // Globals + const globals = pluginOptions.globals || {} // Extract custom tools for the global config const customTools = pluginOptions.mcp?.tools?.map((tool) => ({ @@ -46,11 +48,13 @@ export const mcpPlugin = * For example: * - If a collection has all of its capabilities enabled, admins can allow or disallow the create, update, delete, and find capabilities on that collection. * - If a collection only has the find capability enabled, admins can only allow or disallow the find capability on that collection. + * - If a global has all of its capabilities enabled, admins can allow or disallow the find and update capabilities on that global. * - If a custom tool has gone haywire, admins can disallow that tool. * */ const apiKeyCollection = createAPIKeysCollection( collections, + globals, customTools, experimentalTools, pluginOptions, diff --git a/packages/plugin-mcp/src/mcp/getMcpHandler.ts b/packages/plugin-mcp/src/mcp/getMcpHandler.ts index b050e63699b..bf322fec86e 100644 --- a/packages/plugin-mcp/src/mcp/getMcpHandler.ts +++ b/packages/plugin-mcp/src/mcp/getMcpHandler.ts @@ -7,9 +7,12 @@ import { APIError, configToJSONSchema, type PayloadRequest, type TypedUser } fro import type { MCPAccessSettings, PluginMCPServerConfig } from '../types.js' import { toCamelCase } from '../utils/camelCase.js' +import { getEnabledSlugs } from '../utils/getEnabledSlugs.js' import { registerTool } from './registerTool.js' // Tools +import { findGlobalTool } from './tools/global/find.js' +import { updateGlobalTool } from './tools/global/update.js' import { createResourceTool } from './tools/resource/create.js' import { deleteResourceTool } from './tools/resource/delete.js' import { findResourceTool } from './tools/resource/find.js' @@ -81,6 +84,7 @@ export const getMCPHandler = ( const experimentalTools: NonNullable['tools'] = pluginOptions?.experimental?.tools || {} const collectionsPluginConfig = pluginOptions.collections || {} + const globalsPluginConfig = pluginOptions.globals || {} const collectionsDirPath = experimentalTools && experimentalTools.collections?.collectionsDirPath ? experimentalTools.collections.collectionsDirPath @@ -97,32 +101,8 @@ export const getMCPHandler = ( try { return createMcpHandler( (server) => { - const enabledCollectionSlugs = Object.keys(collectionsPluginConfig || {}).filter( - (collection) => { - const fullyEnabled = - typeof collectionsPluginConfig?.[collection]?.enabled === 'boolean' && - collectionsPluginConfig?.[collection]?.enabled - - if (fullyEnabled) { - return true - } - - const partiallyEnabled = - typeof collectionsPluginConfig?.[collection]?.enabled !== 'boolean' && - ((typeof collectionsPluginConfig?.[collection]?.enabled?.find === 'boolean' && - collectionsPluginConfig?.[collection]?.enabled?.find === true) || - (typeof collectionsPluginConfig?.[collection]?.enabled?.create === 'boolean' && - collectionsPluginConfig?.[collection]?.enabled?.create === true) || - (typeof collectionsPluginConfig?.[collection]?.enabled?.update === 'boolean' && - collectionsPluginConfig?.[collection]?.enabled?.update === true) || - (typeof collectionsPluginConfig?.[collection]?.enabled?.delete === 'boolean' && - collectionsPluginConfig?.[collection]?.enabled?.delete === true)) - - if (partiallyEnabled) { - return true - } - }, - ) + // Get enabled collections + const enabledCollectionSlugs = getEnabledSlugs(collectionsPluginConfig, 'collection') // Collection Operation Tools enabledCollectionSlugs.forEach((enabledCollectionSlug) => { @@ -215,6 +195,62 @@ export const getMCPHandler = ( } }) + // Global Operation Tools + const enabledGlobalSlugs = getEnabledSlugs(globalsPluginConfig, 'global') + + enabledGlobalSlugs.forEach((enabledGlobalSlug) => { + try { + const schema = configSchema.definitions?.[enabledGlobalSlug] as JSONSchema4 + + const toolCapabilities = mcpAccessSettings?.[ + `${toCamelCase(enabledGlobalSlug)}` + ] as Record + const allowFind: boolean | undefined = toolCapabilities?.['find'] as boolean + const allowUpdate: boolean | undefined = toolCapabilities?.['update'] as boolean + + if (allowFind) { + registerTool( + allowFind, + `Find ${enabledGlobalSlug}`, + () => + findGlobalTool( + server, + req, + user, + useVerboseLogs, + enabledGlobalSlug, + globalsPluginConfig, + ), + payload, + useVerboseLogs, + ) + } + if (allowUpdate) { + registerTool( + allowUpdate, + `Update ${enabledGlobalSlug}`, + () => + updateGlobalTool( + server, + req, + user, + useVerboseLogs, + enabledGlobalSlug, + globalsPluginConfig, + schema, + ), + payload, + useVerboseLogs, + ) + } + } catch (error) { + throw new APIError( + `Error registering tools for global ${enabledGlobalSlug}: ${String(error)}`, + 500, + ) + } + }) + // Custom tools customMCPTools.forEach((tool) => { const camelCasedToolName = toCamelCase(tool.name) diff --git a/packages/plugin-mcp/src/mcp/tools/global/find.ts b/packages/plugin-mcp/src/mcp/tools/global/find.ts new file mode 100644 index 00000000000..2390c0ba9c8 --- /dev/null +++ b/packages/plugin-mcp/src/mcp/tools/global/find.ts @@ -0,0 +1,104 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' +import type { PayloadRequest, TypedUser } from 'payload' + +import type { PluginMCPServerConfig } from '../../../types.js' + +import { toCamelCase } from '../../../utils/camelCase.js' +import { toolSchemas } from '../schemas.js' + +export const findGlobalTool = ( + server: McpServer, + req: PayloadRequest, + user: TypedUser, + verboseLogs: boolean, + globalSlug: string, + globals: PluginMCPServerConfig['globals'], +) => { + const tool = async ( + depth: number = 0, + locale?: string, + fallbackLocale?: string, + ): Promise<{ + content: Array<{ + text: string + type: 'text' + }> + }> => { + const payload = req.payload + + if (verboseLogs) { + payload.logger.info( + `[payload-mcp] Reading global: ${globalSlug}, depth: ${depth}${locale ? `, locale: ${locale}` : ''}`, + ) + } + + try { + const findOptions: Parameters[0] = { + slug: globalSlug, + depth, + user, + } + + // Add locale parameters if provided + if (locale) { + findOptions.locale = locale + } + if (fallbackLocale) { + findOptions.fallbackLocale = fallbackLocale + } + + const result = await payload.findGlobal(findOptions) + + if (verboseLogs) { + payload.logger.info(`[payload-mcp] Found global: ${globalSlug}`) + } + + const response = { + content: [ + { + type: 'text' as const, + text: `Global "${globalSlug}": +\`\`\`json +${JSON.stringify(result, null, 2)} +\`\`\``, + }, + ], + } + + return (globals?.[globalSlug]?.overrideResponse?.(response, result, req) || response) as { + content: Array<{ + text: string + type: 'text' + }> + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error' + payload.logger.error(`[payload-mcp] Error reading global ${globalSlug}: ${errorMessage}`) + const response = { + content: [ + { + type: 'text' as const, + text: `❌ **Error reading global "${globalSlug}":** ${errorMessage}`, + }, + ], + } + return (globals?.[globalSlug]?.overrideResponse?.(response, {}, req) || response) as { + content: Array<{ + text: string + type: 'text' + }> + } + } + } + + if (globals?.[globalSlug]?.enabled) { + server.tool( + `find${globalSlug.charAt(0).toUpperCase() + toCamelCase(globalSlug).slice(1)}`, + `${toolSchemas.findGlobal.description.trim()}\n\n${globals?.[globalSlug]?.description || ''}`, + toolSchemas.findGlobal.parameters.shape, + async ({ depth, fallbackLocale, locale }) => { + return await tool(depth, locale, fallbackLocale) + }, + ) + } +} diff --git a/packages/plugin-mcp/src/mcp/tools/global/update.ts b/packages/plugin-mcp/src/mcp/tools/global/update.ts new file mode 100644 index 00000000000..fc2a28be4eb --- /dev/null +++ b/packages/plugin-mcp/src/mcp/tools/global/update.ts @@ -0,0 +1,168 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' +import type { JSONSchema4 } from 'json-schema' +import type { PayloadRequest, TypedUser } from 'payload' + +import { z } from 'zod' + +import type { PluginMCPServerConfig } from '../../../types.js' + +import { toCamelCase } from '../../../utils/camelCase.js' +import { convertCollectionSchemaToZod } from '../../../utils/convertCollectionSchemaToZod.js' +import { toolSchemas } from '../schemas.js' + +export const updateGlobalTool = ( + server: McpServer, + req: PayloadRequest, + user: TypedUser, + verboseLogs: boolean, + globalSlug: string, + globals: PluginMCPServerConfig['globals'], + schema: JSONSchema4, +) => { + const tool = async ( + data: string, + draft: boolean = false, + depth: number = 0, + locale?: string, + fallbackLocale?: string, + ): Promise<{ + content: Array<{ + text: string + type: 'text' + }> + }> => { + const payload = req.payload + + if (verboseLogs) { + payload.logger.info( + `[payload-mcp] Updating global: ${globalSlug}, draft: ${draft}${locale ? `, locale: ${locale}` : ''}`, + ) + } + + try { + // Parse the data JSON + let parsedData: Record + try { + parsedData = JSON.parse(data) + if (verboseLogs) { + payload.logger.info( + `[payload-mcp] Parsed data for ${globalSlug}: ${JSON.stringify(parsedData)}`, + ) + } + } catch (_parseError) { + payload.logger.error(`[payload-mcp] Invalid JSON data provided: ${data}`) + const response = { + content: [{ type: 'text' as const, text: 'Error: Invalid JSON data provided' }], + } + return (globals?.[globalSlug]?.overrideResponse?.(response, {}, req) || response) as { + content: Array<{ + text: string + type: 'text' + }> + } + } + + const updateOptions: Parameters[0] = { + slug: globalSlug, + data: parsedData, + depth, + draft, + user, + } + + // Add locale parameters if provided + if (locale) { + updateOptions.locale = locale + } + if (fallbackLocale) { + updateOptions.fallbackLocale = fallbackLocale + } + + const result = await payload.updateGlobal(updateOptions) + + if (verboseLogs) { + payload.logger.info(`[payload-mcp] Successfully updated global: ${globalSlug}`) + } + + const response = { + content: [ + { + type: 'text' as const, + text: `Global "${globalSlug}" updated successfully! +\`\`\`json +${JSON.stringify(result, null, 2)} +\`\`\``, + }, + ], + } + + return (globals?.[globalSlug]?.overrideResponse?.(response, result, req) || response) as { + content: Array<{ + text: string + type: 'text' + }> + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : 'Unknown error' + payload.logger.error(`[payload-mcp] Error updating global ${globalSlug}: ${errorMessage}`) + + const response = { + content: [ + { + type: 'text' as const, + text: `Error updating global "${globalSlug}": ${errorMessage}`, + }, + ], + } + + return (globals?.[globalSlug]?.overrideResponse?.(response, {}, req) || response) as { + content: Array<{ + text: string + type: 'text' + }> + } + } + } + + if (globals?.[globalSlug]?.enabled) { + const convertedFields = convertCollectionSchemaToZod(schema) + + // Make all fields optional for partial updates (PATCH-style) + const optionalFields = Object.fromEntries( + Object.entries(convertedFields.shape).map(([key, value]) => [key, (value as any).optional()]), + ) + + const updateGlobalSchema = z.object({ + ...optionalFields, + depth: z.number().optional().describe('Optional: Depth of relationships to populate'), + draft: z.boolean().optional().describe('Optional: Whether to save as draft (default: false)'), + fallbackLocale: z + .string() + .optional() + .describe('Optional: fallback locale code to use when requested locale is not available'), + locale: z + .string() + .optional() + .describe( + 'Optional: locale code to update data in (e.g., "en", "es"). Use "all" to update all locales for localized fields', + ), + }) + + server.tool( + `update${globalSlug.charAt(0).toUpperCase() + toCamelCase(globalSlug).slice(1)}`, + `${toolSchemas.updateGlobal.description.trim()}\n\n${globals?.[globalSlug]?.description || ''}`, + updateGlobalSchema.shape, + async (params: Record) => { + const { depth, draft, fallbackLocale, locale, ...rest } = params + const data = JSON.stringify(rest) + return await tool( + data, + draft as boolean, + depth as number, + locale as string, + fallbackLocale as string, + ) + }, + ) + } +} diff --git a/packages/plugin-mcp/src/mcp/tools/schemas.ts b/packages/plugin-mcp/src/mcp/tools/schemas.ts index 3f48504088e..2a16e51dc4b 100644 --- a/packages/plugin-mcp/src/mcp/tools/schemas.ts +++ b/packages/plugin-mcp/src/mcp/tools/schemas.ts @@ -1,6 +1,30 @@ import { z } from 'zod' export const toolSchemas = { + findGlobal: { + description: 'Find a Payload global singleton configuration.', + parameters: z.object({ + depth: z + .number() + .int() + .min(0) + .max(10) + .optional() + .default(0) + .describe('Depth of population for relationships'), + fallbackLocale: z + .string() + .optional() + .describe('Optional: fallback locale code to use when requested locale is not available'), + locale: z + .string() + .optional() + .describe( + 'Optional: locale code to retrieve data in (e.g., "en", "es"). Use "all" to retrieve all locales for localized fields', + ), + }), + }, + findResources: { description: 'Find documents in a collection by ID or where clause using Find or FindByID.', parameters: z.object({ @@ -147,6 +171,32 @@ export const toolSchemas = { }), }, + updateGlobal: { + description: 'Update a Payload global singleton configuration.', + parameters: z.object({ + data: z.string().describe('JSON string containing the data to update'), + depth: z + .number() + .int() + .min(0) + .max(10) + .optional() + .default(0) + .describe('Depth of population for relationships'), + draft: z.boolean().optional().default(false).describe('Whether to update as a draft'), + fallbackLocale: z + .string() + .optional() + .describe('Optional: fallback locale code to use when requested locale is not available'), + locale: z + .string() + .optional() + .describe( + 'Optional: locale code to update data in (e.g., "en", "es"). Use "all" to update all locales for localized fields', + ), + }), + }, + // Experimental Below This Line createCollection: { description: 'Creates a new collection with specified fields and configuration.', diff --git a/packages/plugin-mcp/src/types.ts b/packages/plugin-mcp/src/types.ts index 6184f239c0b..e5a83d244e6 100644 --- a/packages/plugin-mcp/src/types.ts +++ b/packages/plugin-mcp/src/types.ts @@ -1,4 +1,10 @@ -import type { CollectionConfig, CollectionSlug, PayloadRequest, TypedUser } from 'payload' +import type { + CollectionConfig, + CollectionSlug, + GlobalSlug, + PayloadRequest, + TypedUser, +} from 'payload' import type { z } from 'zod' import { type ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js' @@ -115,6 +121,51 @@ export type PluginMCPServerConfig = { } } } + /** + * Set the globals that should be available as resources via MCP. + * Globals are singleton configuration objects (e.g., site settings, navigation). + * Note: Globals only support find and update operations. + */ + globals?: Partial< + Record< + GlobalSlug, + { + /** + * Set the description of the global. This is used by MCP clients to determine when to use the global as a resource. + */ + description?: string + /** + * Set the enabled capabilities of the global. Admins can then allow or disallow the use of the capability by MCP clients. + * Note: Globals only support find and update operations as they are singletons. + */ + enabled: + | { + find?: boolean + update?: boolean + } + | boolean + + /** + * Override the response generated by the MCP client. This allows you to modify the response that is sent to the MCP client. This is useful for adding additional data to the response, data normalization, or verifying data. + */ + overrideResponse?: ( + response: { + content: Array<{ + text: string + type: string + }> + }, + doc: Record, + req: PayloadRequest, + ) => { + content: Array<{ + text: string + type: string + }> + } + } + > + > /** * MCP Server options. */ @@ -349,6 +400,11 @@ export type MCPAccessSettings = { find?: boolean update?: boolean } + custom?: Record + globals?: { + find?: boolean + update?: boolean + } jobs?: { create?: boolean run?: boolean @@ -360,6 +416,8 @@ export type MCPAccessSettings = { user: TypedUser } & Record +export type EntityConfig = PluginMCPServerConfig['collections'] | PluginMCPServerConfig['globals'] + export type FieldDefinition = { description?: string name: string diff --git a/packages/plugin-mcp/src/utils/adminEntitySettings.ts b/packages/plugin-mcp/src/utils/adminEntitySettings.ts new file mode 100644 index 00000000000..a11fdde05af --- /dev/null +++ b/packages/plugin-mcp/src/utils/adminEntitySettings.ts @@ -0,0 +1,40 @@ +/** + * Defines the default admin entity settings for Collections and Globals. + * This is used to create the MCP API key permission fields for the API Keys collection. + */ +export const adminEntitySettings = { + collection: [ + { + name: 'find', + description: (slug: string) => `Allow clients to find ${slug}.`, + label: 'Find', + }, + { + name: 'create', + description: (slug: string) => `Allow clients to create ${slug}.`, + label: 'Create', + }, + { + name: 'update', + description: (slug: string) => `Allow clients to update ${slug}.`, + label: 'Update', + }, + { + name: 'delete', + description: (slug: string) => `Allow clients to delete ${slug}.`, + label: 'Delete', + }, + ], + global: [ + { + name: 'find', + description: (slug: string) => `Allow clients to find ${slug} global.`, + label: 'Find', + }, + { + name: 'update', + description: (slug: string) => `Allow clients to update ${slug} global.`, + label: 'Update', + }, + ], +} diff --git a/packages/plugin-mcp/src/utils/createApiKeyFields.ts b/packages/plugin-mcp/src/utils/createApiKeyFields.ts new file mode 100644 index 00000000000..243f90c1378 --- /dev/null +++ b/packages/plugin-mcp/src/utils/createApiKeyFields.ts @@ -0,0 +1,72 @@ +import type { Field } from 'payload' + +import type { EntityConfig } from '../types.js' + +import { adminEntitySettings } from './adminEntitySettings.js' +import { toCamelCase } from './camelCase.js' +import { getEnabledSlugs } from './getEnabledSlugs.js' +/** + * Creates MCP API key permission fields using collections or globals. + * Generates collapsible field groups with checkboxes for each enabled operation. + * + * @param config - The collections or globals configuration object + * @param configType - The type of configuration ('collection' or 'global') + * @returns Array of fields for the MCP API Keys collection + */ +export const createApiKeyFields = ({ + config, + configType, +}: { + config: EntityConfig | undefined + configType: 'collection' | 'global' +}): Field[] => { + const operations = adminEntitySettings[configType] + const enabledSlugs = getEnabledSlugs(config, configType) + + return enabledSlugs.map((slug) => { + const entityConfig = config?.[slug] + + const enabledOperations = operations.filter((operation) => { + // If fully enabled, all operations are available + if (entityConfig?.enabled === true) { + return true + } + + // If partially enabled, check if this specific operation is enabled + const enabled = entityConfig?.enabled + if (typeof enabled !== 'boolean' && enabled) { + const operationEnabled = enabled[operation.name as keyof typeof enabled] + return typeof operationEnabled === 'boolean' && operationEnabled === true + } + + return false + }) + + // Generate checkbox fields for each enabled operation + const operationFields = enabledOperations.map((operation) => ({ + name: operation.name, + type: 'checkbox' as const, + admin: { + description: operation.description(slug), + }, + defaultValue: false, + label: operation.label, + })) + + return { + type: 'collapsible' as const, + admin: { + position: 'sidebar' as const, + }, + fields: [ + { + name: toCamelCase(slug), + type: 'group' as const, + fields: operationFields, + label: configType, + }, + ], + label: `${slug.charAt(0).toUpperCase() + toCamelCase(slug).slice(1)}`, + } + }) +} diff --git a/packages/plugin-mcp/src/utils/getEnabledSlugs.ts b/packages/plugin-mcp/src/utils/getEnabledSlugs.ts new file mode 100644 index 00000000000..9d2fd16b832 --- /dev/null +++ b/packages/plugin-mcp/src/utils/getEnabledSlugs.ts @@ -0,0 +1,42 @@ +import type { EntityConfig } from '../types.js' + +import { adminEntitySettings } from './adminEntitySettings.js' + +/** + * Extracts enabled slugs from collections or globals configuration. + * A slug is considered enabled if: + * 1. enabled is set to true (fully enabled) + * 2. enabled is an object with at least one operation set to true + * + * @param config - The collections or globals configuration object + * @param configType - The type of configuration ('collection' or 'global') + * @returns Array of enabled slugs + */ +export const getEnabledSlugs = ( + config: EntityConfig | undefined, + configType: 'collection' | 'global', +): string[] => { + return Object.keys(config || {}).filter((slug) => { + const entityConfig = config?.[slug] + const operations = adminEntitySettings[configType] + + // Check if fully enabled (boolean true) + const fullyEnabled = + typeof entityConfig?.enabled === 'boolean' && entityConfig?.enabled === true + + if (fullyEnabled) { + return true + } + + // Check if partially enabled (at least one operation is enabled) + const enabled = entityConfig?.enabled + if (typeof enabled !== 'boolean' && enabled) { + return operations.some((operation) => { + const operationEnabled = enabled[operation.name as keyof typeof enabled] + return typeof operationEnabled === 'boolean' && operationEnabled === true + }) + } + + return false + }) +} diff --git a/test/plugin-mcp/config.ts b/test/plugin-mcp/config.ts index deee021f0d5..7cc610b7c72 100644 --- a/test/plugin-mcp/config.ts +++ b/test/plugin-mcp/config.ts @@ -12,6 +12,7 @@ import { Products } from './collections/Products.js' import { ReturnedResources } from './collections/ReturnedResources.js' import { Rolls } from './collections/Rolls.js' import { Users } from './collections/Users.js' +import { SiteSettings } from './globals/SiteSettings.js' import { seed } from './seed/index.js' const filename = fileURLToPath(import.meta.url) @@ -42,6 +43,7 @@ export default buildConfigWithDefaults({ }, ], }, + globals: [SiteSettings], onInit: seed, plugins: [ mcpPlugin({ @@ -118,6 +120,15 @@ export default buildConfigWithDefaults({ description: 'This is a Payload collection with Media documents.', }, }, + globals: { + 'site-settings': { + enabled: { + find: true, + update: true, + }, + description: 'Site-wide configuration settings.', + }, + }, mcp: { handlerOptions: { verboseLogs: true, diff --git a/test/plugin-mcp/globals/SiteSettings.ts b/test/plugin-mcp/globals/SiteSettings.ts new file mode 100644 index 00000000000..2b952483f40 --- /dev/null +++ b/test/plugin-mcp/globals/SiteSettings.ts @@ -0,0 +1,37 @@ +import type { GlobalConfig } from 'payload' + +export const SiteSettings: GlobalConfig = { + slug: 'site-settings', + fields: [ + { + name: 'siteName', + type: 'text', + required: true, + admin: { + description: 'The name of the site', + }, + }, + { + name: 'siteDescription', + type: 'textarea', + admin: { + description: 'A brief description of the site', + }, + }, + { + name: 'maintenanceMode', + type: 'checkbox', + defaultValue: false, + admin: { + description: 'Enable or disable maintenance mode', + }, + }, + { + name: 'contactEmail', + type: 'email', + admin: { + description: 'Contact email address for the site', + }, + }, + ], +} diff --git a/test/plugin-mcp/int.spec.ts b/test/plugin-mcp/int.spec.ts index 6f307150660..ab70d49a5a5 100644 --- a/test/plugin-mcp/int.spec.ts +++ b/test/plugin-mcp/int.spec.ts @@ -50,15 +50,23 @@ async function parseStreamResponse(response: Response): Promise { } } -const getApiKey = async (enableUpdate = false, enableDelete = false): Promise => { +const getApiKey = async ( + enableUpdate: boolean = false, + enableDelete: boolean = false, + globalFind: boolean = false, + globalUpdate: boolean = false, +): Promise => { const doc = await payload.create({ collection: 'payload-mcp-api-keys', data: { enableAPIKey: true, label: 'Test API Key', - // @ts-expect-error - update is not a valid property + // @ts-expect-error - update is a valid property posts: { find: true, create: true, update: enableUpdate, delete: enableDelete }, products: { find: true }, + ...(globalFind || globalUpdate + ? { siteSettings: { find: globalFind, update: globalUpdate } } + : {}), apiKey: randomUUID(), user: userId, }, @@ -761,6 +769,67 @@ describe('@payloadcms/plugin-mcp', () => { ) }) + it('should find site-settings global', async () => { + const apiKey = await getApiKey(false, false, true) + const response = await restClient.POST('/mcp', { + headers: { + Authorization: `Bearer ${apiKey}`, + Accept: 'application/json, text/event-stream', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + id: 1, + jsonrpc: '2.0', + method: 'tools/call', + params: { + name: 'findSiteSettings', + arguments: {}, + }, + }), + }) + + const json = await parseStreamResponse(response) + + expect(json).toBeDefined() + expect(json.result).toBeDefined() + expect(json.result.content).toBeDefined() + expect(json.result.content[0].type).toBe('text') + expect(json.result.content[0].text).toContain('Global "site-settings"') + expect(json.result.content[0].text).toContain('```json') + }) + + it('should update site-settings global', async () => { + const apiKey = await getApiKey(false, false, true, true) + const response = await restClient.POST('/mcp', { + headers: { + Authorization: `Bearer ${apiKey}`, + Accept: 'application/json, text/event-stream', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + id: 1, + jsonrpc: '2.0', + method: 'tools/call', + params: { + name: 'updateSiteSettings', + arguments: { + siteName: 'MCP Test Site', + siteDescription: 'A test site for MCP global operations', + maintenanceMode: false, + }, + }, + }), + }) + + const json = await parseStreamResponse(response) + + expect(json).toBeDefined() + expect(json.result).toBeDefined() + expect(json.result.content).toBeDefined() + expect(json.result.content[0].type).toBe('text') + expect(json.result.content[0].text).toContain('Global "site-settings" updated successfully') + }) + describe('Localization', () => { it('should include locale parameters in tool schemas', async () => { const apiKey = await getApiKey(true, true) @@ -1045,4 +1114,35 @@ describe('@payloadcms/plugin-mcp', () => { expect(json.result.content[0].text).toContain('"content": "Hello World."') }) }) + + it('should include globals in tools list', async () => { + const apiKey = await getApiKey(false, false, true, true) + const response = await restClient.POST('/mcp', { + headers: { + Authorization: `Bearer ${apiKey}`, + Accept: 'application/json, text/event-stream', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + id: 1, + jsonrpc: '2.0', + method: 'tools/list', + params: {}, + }), + }) + + const json = await parseStreamResponse(response) + + expect(json).toBeDefined() + expect(json.result).toBeDefined() + expect(json.result.tools).toBeDefined() + + const findGlobalTool = json.result.tools.find((t: any) => t.name === 'findSiteSettings') + expect(findGlobalTool).toBeDefined() + expect(findGlobalTool.description).toContain('Payload global') + + const updateGlobalTool = json.result.tools.find((t: any) => t.name === 'updateSiteSettings') + expect(updateGlobalTool).toBeDefined() + expect(updateGlobalTool.description).toContain('Payload global') + }) }) diff --git a/test/plugin-mcp/payload-types.ts b/test/plugin-mcp/payload-types.ts index e5d72bf2909..f37367b6a98 100644 --- a/test/plugin-mcp/payload-types.ts +++ b/test/plugin-mcp/payload-types.ts @@ -99,8 +99,12 @@ export interface Config { db: { defaultIDType: string; }; - globals: {}; - globalsSelect: {}; + globals: { + 'site-settings': SiteSetting; + }; + globalsSelect: { + 'site-settings': SiteSettingsSelect | SiteSettingsSelect; + }; locale: null; user: | (User & { @@ -350,6 +354,16 @@ export interface PayloadMcpApiKey { */ update?: boolean | null; }; + siteSettings?: { + /** + * Allow clients to find site-settings global. + */ + find?: boolean | null; + /** + * Allow clients to update site-settings global. + */ + update?: boolean | null; + }; 'payload-mcp-tool'?: { /** * Rolls a virtual dice with a specified number of sides @@ -684,6 +698,12 @@ export interface PayloadMcpApiKeysSelect { find?: T; update?: T; }; + siteSettings?: + | T + | { + find?: T; + update?: T; + }; 'payload-mcp-tool'?: | T | { @@ -778,6 +798,44 @@ export interface PayloadMigrationsSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "site-settings". + */ +export interface SiteSetting { + id: string; + /** + * The name of the site + */ + siteName: string; + /** + * A brief description of the site + */ + siteDescription?: string | null; + /** + * Enable or disable maintenance mode + */ + maintenanceMode?: boolean | null; + /** + * Contact email address for the site + */ + contactEmail?: string | null; + updatedAt?: string | null; + createdAt?: string | null; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "site-settings_select". + */ +export interface SiteSettingsSelect { + siteName?: T; + siteDescription?: T; + maintenanceMode?: T; + contactEmail?: T; + updatedAt?: T; + createdAt?: T; + globalType?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "auth". From 4593ae0113fde238baf6cc1bc54c2b0374fa17bb Mon Sep 17 00:00:00 2001 From: German Jablonski <43938777+GermanJablo@users.noreply.github.com> Date: Tue, 6 Jan 2026 21:22:39 +0000 Subject: [PATCH 58/67] fix(richtext-lexical,ui): make uploadNode default to `alt` user-defined values. (#15097) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #14780 There are 2 ways a user can add fields to UploadNode within richtext: ```ts // 1. Media Collection export const Media: CollectionConfig = { slug: 'media', fields: [ { name: 'alt', type: 'text' } // ← Default alt for the image ], upload: true, } // 2. UploadFeature in Lexical (Per-instance override) UploadFeature({ collections: { media: { fields: [ { name: 'alt', type: 'text' } // ← Context-specific alt per usage ] } } }) ``` This PR updates all upload converters (JSX, HTML async/sync, Slate, and UI components) to intelligently resolve the `alt` attribute with the following priority: 1. **UploadFeature `fields.alt`** - Context-specific override 2. **Media collection `alt`** - Default from document 3. **Empty string** - Accessibility fallback (instead of using filename) This prevents users from having to manually override converters to achieve proper alt text handling. **Implementation note:** Type assertions are required since both `alt` fields are user-defined and don't exist in the core types at compile time. --- .../RenderFieldsToDiff/fields/Upload/index.tsx | 5 ++++- .../lexicalToHtml/async/converters/upload.ts | 6 ++++-- .../lexicalToHtml/sync/converters/upload.ts | 6 ++++-- .../lexicalToJSX/converter/converters/upload.tsx | 14 ++++---------- .../src/features/upload/server/index.ts | 9 +++++++-- .../src/field/Diff/converters/upload/index.tsx | 10 +++------- .../src/field/elements/upload/Element/index.tsx | 4 +++- packages/ui/src/elements/PreviewSizes/index.tsx | 10 ++++++++-- 8 files changed, 37 insertions(+), 27 deletions(-) diff --git a/packages/next/src/views/Version/RenderFieldsToDiff/fields/Upload/index.tsx b/packages/next/src/views/Version/RenderFieldsToDiff/fields/Upload/index.tsx index ccd5b44accb..d27b3c77479 100644 --- a/packages/next/src/views/Version/RenderFieldsToDiff/fields/Upload/index.tsx +++ b/packages/next/src/views/Version/RenderFieldsToDiff/fields/Upload/index.tsx @@ -279,6 +279,9 @@ const UploadDocumentDiff = (args: { id = uploadDoc } + const alt = + (value && typeof value === 'object' && (value as { alt?: string }).alt) || filename || '' + return (
- {thumbnailSRC?.length ? {filename} : } + {thumbnailSRC?.length ? {alt} : }
{pillLabel && (
diff --git a/packages/richtext-lexical/src/features/converters/lexicalToHtml/async/converters/upload.ts b/packages/richtext-lexical/src/features/converters/lexicalToHtml/async/converters/upload.ts index 61cc5fc13ea..f7aec617011 100644 --- a/packages/richtext-lexical/src/features/converters/lexicalToHtml/async/converters/upload.ts +++ b/packages/richtext-lexical/src/features/converters/lexicalToHtml/async/converters/upload.ts @@ -27,6 +27,8 @@ export const UploadHTMLConverterAsync: HTMLConvertersAsync return '' } + const alt = (node.fields?.alt as string) || (uploadDoc as { alt?: string })?.alt || '' + const url = uploadDoc.url // 1) If upload is NOT an image, return a link @@ -38,7 +40,7 @@ export const UploadHTMLConverterAsync: HTMLConvertersAsync if (!uploadDoc.sizes || !Object.keys(uploadDoc.sizes).length) { return ` pictureHTML += ` ${uploadDoc.filename} = { return '' } + const alt = (node.fields?.alt as string) || (uploadDoc as { alt?: string })?.alt || '' + const url = uploadDoc.url // 1) If upload is NOT an image, return a link @@ -32,7 +34,7 @@ export const UploadHTMLConverter: HTMLConverters = { if (!uploadDoc.sizes || !Object.keys(uploadDoc.sizes).length) { return ` = { pictureHTML += ` ${uploadDoc.filename} = { const uploadDoc = uploadNode.value as FileData & TypeWithID + const alt = (uploadNode.fields?.alt as string) || (uploadDoc as { alt?: string })?.alt || '' + const url = uploadDoc.url /** @@ -31,9 +33,7 @@ export const UploadJSXConverter: JSXConverters = { * If the upload is a simple image with no different sizes, return a simple img tag */ if (!uploadDoc.sizes || !Object.keys(uploadDoc.sizes).length) { - return ( - {uploadDoc.filename} - ) + return {alt} } /** @@ -71,13 +71,7 @@ export const UploadJSXConverter: JSXConverters = { // Add the default img tag pictureJSX.push( - {uploadDoc?.filename}, + {alt}, ) return {pictureJSX} }, diff --git a/packages/richtext-lexical/src/features/upload/server/index.ts b/packages/richtext-lexical/src/features/upload/server/index.ts index 4f234cd9e0e..2d4249a673c 100644 --- a/packages/richtext-lexical/src/features/upload/server/index.ts +++ b/packages/richtext-lexical/src/features/upload/server/index.ts @@ -177,6 +177,11 @@ export const UploadFeature = createServerFeature< const url = getAbsoluteURL(uploadDocument?.value?.url ?? '', req?.payload) + const alt = + (node.fields?.alt as string) || + (uploadDocument?.value as { alt?: string })?.alt || + '' + /** * If the upload is not an image, return a link to the upload */ @@ -191,7 +196,7 @@ export const UploadFeature = createServerFeature< !uploadDocument?.value?.sizes || !Object.keys(uploadDocument?.value?.sizes).length ) { - return `${uploadDocument?.value?.filename}` + return `${alt}` } /** @@ -220,7 +225,7 @@ export const UploadFeature = createServerFeature< } // Add the default img tag - pictureHTML += `Image` + pictureHTML += `${alt}` pictureHTML += '' return pictureHTML } else { diff --git a/packages/richtext-lexical/src/field/Diff/converters/upload/index.tsx b/packages/richtext-lexical/src/field/Diff/converters/upload/index.tsx index bf0e280dc64..ccca83bf0b1 100644 --- a/packages/richtext-lexical/src/field/Diff/converters/upload/index.tsx +++ b/packages/richtext-lexical/src/field/Diff/converters/upload/index.tsx @@ -18,7 +18,7 @@ const baseClass = 'lexical-upload-diff' export const UploadDiffHTMLConverterAsync: (args: { i18n: I18nClient req: PayloadRequest -}) => HTMLConvertersAsync = ({ i18n, req }) => { +}) => HTMLConvertersAsync = () => { return { upload: async ({ node, populate, providedCSSString }) => { const uploadNode = node as UploadDataImproved @@ -42,7 +42,7 @@ export const UploadDiffHTMLConverterAsync: (args: { return '' } - const relatedCollection = req.payload.collections[uploadNode.relationTo]?.config + const alt = (node.fields?.alt as string) || (uploadDoc as { alt?: string })?.alt || '' const thumbnailSRC: string = ('thumbnailURL' in uploadDoc && (uploadDoc?.thumbnailURL as string)) || uploadDoc?.url || '' @@ -66,11 +66,7 @@ export const UploadDiffHTMLConverterAsync: (args: { >
- {thumbnailSRC?.length ? ( - {uploadDoc?.filename} - ) : ( - - )} + {thumbnailSRC?.length ? {alt} : }
{uploadDoc?.filename} diff --git a/packages/richtext-slate/src/field/elements/upload/Element/index.tsx b/packages/richtext-slate/src/field/elements/upload/Element/index.tsx index 61623209b87..76b3e37a45a 100644 --- a/packages/richtext-slate/src/field/elements/upload/Element/index.tsx +++ b/packages/richtext-slate/src/field/elements/upload/Element/index.tsx @@ -136,6 +136,8 @@ const UploadElementComponent: React.FC<{ enabledCollectionSlugs?: string[] }> = const relatedFieldSchemaPath = `${uploadFieldsSchemaPath}.${relatedCollection.slug}` const customFieldsMap = fieldProps.componentMap[relatedFieldSchemaPath] + const alt = (data as { alt?: string })?.alt || data?.filename || '' + return (
=
{/* TODO: migrate to use Thumbnail component */}
- {thumbnailSRC ? {data?.filename} : } + {thumbnailSRC ? {alt} : }
diff --git a/packages/ui/src/elements/PreviewSizes/index.tsx b/packages/ui/src/elements/PreviewSizes/index.tsx index a33041cd9ec..f75889f00ef 100644 --- a/packages/ui/src/elements/PreviewSizes/index.tsx +++ b/packages/ui/src/elements/PreviewSizes/index.tsx @@ -33,6 +33,7 @@ const sortSizes = (sizes: FilesSizesWithUrl, imageSizes: SanitizedUploadConfig[' type PreviewSizeCardProps = { active: boolean + alt: string meta: FileInfo name: string onClick?: () => void @@ -41,6 +42,7 @@ type PreviewSizeCardProps = { const PreviewSizeCard: React.FC = ({ name, active, + alt, meta, onClick, previewSrc, @@ -63,7 +65,7 @@ const PreviewSizeCard: React.FC = ({ tabIndex={0} >
- {meta.filename} + {alt}
{name}
@@ -85,6 +87,8 @@ export const PreviewSizes: React.FC = ({ doc, imageCacheTag, const { imageSizes } = uploadConfig const { sizes } = doc + const alt = (doc as { alt?: string })?.alt || doc.filename || '' + const [orderedSizes, setOrderedSizes] = useState(() => sortSizes(sizes, imageSizes), ) @@ -126,12 +130,13 @@ export const PreviewSizes: React.FC = ({ doc, imageCacheTag,
{selectedSize || originalFilename}
- {doc.filename} + {alt}
setSelectedSize(null)} @@ -146,6 +151,7 @@ export const PreviewSizes: React.FC = ({ doc, imageCacheTag, return ( Date: Tue, 6 Jan 2026 16:22:58 -0500 Subject: [PATCH 59/67] feat(plugin-search): enables skipping of document syncing (#14928) ### Summary Adds the `skipSync` property which allows you to conditionally skip syncing documents to the search index based on locale, document properties, or other criteria. ### Changes - Added `skipSync` function that returns boolean (true = skip, false = sync) - Called once per locale+document combination - Added documentation with multi-tenant example ### API ```ts skipSync: async ({ locale, doc, collectionSlug, req }) => { if (!locale) return false const tenant = await req.payload.findByID({ collection: 'tenants', id: doc.tenant.id, }) return !tenant.allowedLocales.includes(locale) } ``` --------- Co-authored-by: Claude Sonnet 4.5 --- docs/plugins/search.mdx | 42 +++++ packages/plugin-search/src/index.ts | 11 +- packages/plugin-search/src/types.ts | 39 +++- .../src/utilities/generateReindexHandler.ts | 84 ++++++--- .../src/utilities/syncDocAsSearchIndex.ts | 134 +++++++------ test/_community/payload-types.ts | 28 +-- test/plugin-search/config.ts | 26 ++- test/plugin-search/int.spec.ts | 176 ++++++++++++++++++ test/plugin-search/payload-types.ts | 61 ++++++ 9 files changed, 487 insertions(+), 114 deletions(-) diff --git a/docs/plugins/search.mdx b/docs/plugins/search.mdx index faf873c4336..b5ea6e6b884 100644 --- a/docs/plugins/search.mdx +++ b/docs/plugins/search.mdx @@ -161,6 +161,48 @@ When `syncDrafts` is true, draft documents will be synced to search. This is fal If true, will delete documents from search whose status changes to draft. This is true by default. You must have [Payload Drafts](https://payloadcms.com/docs/versions/drafts) enabled for this to apply. +#### `skipSync` + +The `skipSync` function allows you to conditionally skip syncing specific documents to the search index based on locale, document properties, or any other criteria. This is particularly useful for multi-tenant applications where different tenants use different languages, or when you need fine-grained control over what gets indexed. + +This function is called once per locale per document and should return `true` to skip syncing or `false` to proceed. + +```ts +// payload.config.ts +{ + // ... + searchPlugin({ + skipSync: async ({ locale, doc, collectionSlug, req }) => { + // Skip syncing for non-localized collections + if (!locale) return false + + // Example: Multi-tenant locale filtering + // Only index locales that are enabled for this document's tenant + const tenant = await req.payload.findByID({ + collection: 'tenants', + id: doc.tenant.id, + }) + + return !tenant.allowedLocales.includes(locale) + }, + }), +} +``` + +**Parameters:** + +- `locale`: The locale being synced (e.g., `'en'`, `'es'`), or `undefined` +- `doc`: The document being synced +- `collectionSlug`: The slug of the collection being synced +- `req`: The Payload request object + +**Common use cases:** + +- Multi-tenant applications with per-tenant locale restrictions +- Skipping indexing for specific document states or flags +- Conditional indexing based on user permissions or roles +- Excluding certain locales for specific document types + #### `reindexBatchSize` A number that, when specified, will be used as the value to determine how many search documents to fetch for reindexing at a time in each batch. If not set, this will default to `50`. diff --git a/packages/plugin-search/src/index.ts b/packages/plugin-search/src/index.ts index fc4be4bd5d1..f7fcc27ac6f 100644 --- a/packages/plugin-search/src/index.ts +++ b/packages/plugin-search/src/index.ts @@ -9,7 +9,7 @@ import { generateSearchCollection } from './Search/index.js' type CollectionAfterChangeHookArgs = Parameters[0] export const searchPlugin = - (incomingPluginConfig: SearchPluginConfig) => + (incomingPluginConfig: SearchPluginConfig) => (config: Config): Config => { const { collections } = config @@ -22,23 +22,16 @@ export const searchPlugin = incomingPluginConfig.localize = shouldLocalize if (collections) { - const locales = config.localization - ? config.localization.locales.map((localeConfig) => - typeof localeConfig === 'string' ? localeConfig : localeConfig.code, - ) - : [] - const labels = Object.fromEntries( collections .filter(({ slug }) => incomingPluginConfig.collections?.includes(slug)) .map((collection) => [collection.slug, collection.labels]), ) - const pluginConfig: SanitizedSearchPluginConfig = { + const pluginConfig: SanitizedSearchPluginConfig = { // write any config defaults here deleteDrafts: true, labels, - locales, reindexBatchSize: incomingPluginConfig?.reindexBatchSize || 50, syncDrafts: false, ...incomingPluginConfig, diff --git a/packages/plugin-search/src/types.ts b/packages/plugin-search/src/types.ts index a3d07c580d2..221c52843ca 100644 --- a/packages/plugin-search/src/types.ts +++ b/packages/plugin-search/src/types.ts @@ -29,7 +29,14 @@ export type BeforeSync = (args: { export type FieldsOverride = (args: { defaultFields: Field[] }) => Field[] -export type SearchPluginConfig = { +export type SkipSyncFunction = (args: { + collectionSlug: string + doc: any + locale: ConfigTypes extends { locale: unknown } ? ConfigTypes['locale'] : string | undefined + req: PayloadRequest +}) => boolean | Promise + +export type SearchPluginConfig = { /** * @deprecated * This plugin gets the api route from the config directly and does not need to be passed in. @@ -56,6 +63,27 @@ export type SearchPluginConfig = { */ reindexBatchSize?: number searchOverrides?: { fields?: FieldsOverride } & Partial> + /** + * Determine whether to skip syncing a document for a specific locale. + * Useful for multi-tenant applications, conditional indexing, or any scenario where + * sync behavior should vary by locale, document, or other factors. + * + * @default undefined - All configured locales will be synced + * + * @example + * // Skip syncing based on document's tenant settings + * skipSync: async ({ locale, req, doc, collectionSlug }) => { + * // For non-localized collections, locale will be undefined + * if (!locale) return false + * + * const tenant = await req.payload.findByID({ + * collection: 'tenants', + * id: doc.tenant.id + * }) + * return !tenant.allowedLocales.includes(locale) + * } + */ + skipSync?: SkipSyncFunction /** * Controls whether drafts are synced to the search index * @@ -72,15 +100,14 @@ export type ResolvedCollectionLabels = { [collection: string]: StaticLabel } -export type SearchPluginConfigWithLocales = { +export type SearchPluginConfigWithLocales = { labels?: CollectionLabels - locales?: string[] -} & SearchPluginConfig +} & SearchPluginConfig -export type SanitizedSearchPluginConfig = { +export type SanitizedSearchPluginConfig = { reindexBatchSize: number syncDrafts: boolean -} & SearchPluginConfigWithLocales +} & SearchPluginConfigWithLocales export type SyncWithSearchArgs = { collection: string diff --git a/packages/plugin-search/src/utilities/generateReindexHandler.ts b/packages/plugin-search/src/utilities/generateReindexHandler.ts index 9fa13220d76..90a6ba0235f 100644 --- a/packages/plugin-search/src/utilities/generateReindexHandler.ts +++ b/packages/plugin-search/src/utilities/generateReindexHandler.ts @@ -30,13 +30,8 @@ export const generateReindexHandler = const searchSlug = pluginConfig?.searchOverrides?.slug || 'search' const searchCollections = pluginConfig?.collections || [] - const reindexLocales = pluginConfig?.locales?.length - ? pluginConfig.locales - : req.locale - ? [req.locale] - : [] - const validatePermissions = async (): Promise => { + async function validatePermissions(): Promise { const accessResults = await getAccessResults({ req }) const searchAccessResults = accessResults.collections?.[searchSlug] if (!searchAccessResults) { @@ -59,7 +54,7 @@ export const generateReindexHandler = : { isValid: false, message: t('error:notAllowedToPerformAction') } } - const validateCollections = (): ValidationResult => { + function validateCollections(): ValidationResult { const collectionsAreValid = collections.every((col) => searchCollections.includes(col)) return collections.length && collectionsAreValid ? { isValid: true } @@ -98,7 +93,7 @@ export const generateReindexHandler = let aggregateErrors = 0 let aggregateDocs = 0 - const countDocuments = async (collection: string, drafts?: boolean): Promise => { + async function countDocuments(collection: string, drafts?: boolean): Promise { const { totalDocs } = await payload.count({ collection, ...defaultLocalApiProps, @@ -108,7 +103,7 @@ export const generateReindexHandler = return totalDocs } - const deleteIndexes = async (collection: string) => { + async function deleteIndexes(collection: string) { await payload.delete({ collection: searchSlug, depth: 0, @@ -118,7 +113,7 @@ export const generateReindexHandler = }) } - const reindexCollection = async (collection: string) => { + async function reindexCollection(collection: string) { const draftsEnabled = Boolean(payload.collections[collection]?.config.versions?.drafts) const totalDocsWithDrafts = await countDocuments(collection, true) @@ -131,23 +126,58 @@ export const generateReindexHandler = aggregateDocsWithDrafts += totalDocsWithDrafts aggregateDocs += totalDocs - for (let j = 0; j < reindexLocales.length; j++) { - // create first index, then we update with other locales accordingly - const operation = j === 0 ? 'create' : 'update' - const localeToSync = reindexLocales[j] - - for (let i = 0; i < totalBatches; i++) { - const { docs } = await payload.find({ - collection, - depth: 0, - limit: batchSize, - locale: localeToSync, - page: i + 1, - where: syncDrafts || !draftsEnabled ? undefined : whereStatusPublished, - ...defaultLocalApiProps, - }) - - for (const doc of docs) { + // Loop through batches, then documents, then locales per document + for (let i = 0; i < totalBatches; i++) { + const defaultLocale = req.payload.config.localization + ? req.payload.config.localization.defaultLocale + : req.locale + + const { docs } = await payload.find({ + collection, + depth: 0, + limit: batchSize, + locale: defaultLocale, + page: i + 1, + where: syncDrafts || !draftsEnabled ? undefined : whereStatusPublished, + ...defaultLocalApiProps, + }) + + for (const doc of docs) { + // Get all configured locales + // If no localization, use [undefined] to sync once without a locale + const allLocales = req.payload.config.localization + ? req.payload.config.localization.localeCodes + : [undefined] + + // Loop through all locales and check each one + let firstAllowedLocale = true + for (const localeToSync of allLocales) { + // Check if we should skip this locale for this document + let shouldSkip = false + if (typeof pluginConfig.skipSync === 'function') { + try { + shouldSkip = await pluginConfig.skipSync({ + collectionSlug: collection, + doc, + locale: localeToSync, + req, + }) + } catch (err) { + req.payload.logger.error({ + err, + msg: 'Search plugin: Error executing skipSync. Proceeding with sync.', + }) + } + } + + if (shouldSkip) { + continue // Skip this locale + } + + // Sync this locale (create first index, then update with other locales accordingly) + const operation = firstAllowedLocale ? 'create' : 'update' + firstAllowedLocale = false + await syncDocAsSearchIndex({ collection, data: doc, diff --git a/packages/plugin-search/src/utilities/syncDocAsSearchIndex.ts b/packages/plugin-search/src/utilities/syncDocAsSearchIndex.ts index 31c1471f6ff..55028ba53f9 100644 --- a/packages/plugin-search/src/utilities/syncDocAsSearchIndex.ts +++ b/packages/plugin-search/src/utilities/syncDocAsSearchIndex.ts @@ -15,7 +15,29 @@ export const syncDocAsSearchIndex = async ({ const { beforeSync, defaultPriorities, deleteDrafts, searchOverrides, syncDrafts } = pluginConfig const searchSlug = searchOverrides?.slug || 'search' - const syncLocale = locale || req.locale + + // Determine sync locale + const syncLocale = locale || req.locale || undefined + + if (typeof pluginConfig.skipSync === 'function') { + try { + const skipSync = await pluginConfig.skipSync({ + collectionSlug: collection, + doc, + locale: syncLocale, + req, + }) + + if (skipSync) { + return doc + } + } catch (err) { + req.payload.logger.error({ + err, + msg: 'Search plugin: Error executing skipSync. Proceeding with sync.', + }) + } + } let dataToSave: DocToSync = { doc: { @@ -25,7 +47,7 @@ export const syncDocAsSearchIndex = async ({ title, } const docKeyPrefix = `${collection}:${id}` - const docKey = pluginConfig.locales?.length ? `${docKeyPrefix}:${syncLocale}` : docKeyPrefix + const docKey = req.payload.config.localization ? `${docKeyPrefix}:${syncLocale}` : docKeyPrefix const syncedDocsSet = (req.context?.syncedDocsSet as Set) || new Set() if (syncedDocsSet.has(docKey)) { @@ -145,25 +167,6 @@ export const syncDocAsSearchIndex = async ({ if (foundDoc) { const { id: searchDocID } = foundDoc - if (doSync) { - // update the doc normally - try { - await payload.update({ - id: searchDocID, - collection: searchSlug, - data: { - ...dataToSave, - priority: foundDoc.priority || defaultPriority, - }, - depth: 0, - locale: syncLocale, - req, - }) - } catch (err: unknown) { - payload.logger.error({ err, msg: `Error updating ${searchSlug} document.` }) - } - } - // Check if document is trashed and delete from search const isTrashDocument = doc && 'deletedAt' in doc && doc.deletedAt @@ -181,48 +184,67 @@ export const syncDocAsSearchIndex = async ({ msg: `Error deleting ${searchSlug} document for trashed doc.`, }) } - } - - if (deleteDrafts && status === 'draft') { - // Check to see if there's a published version of the doc - // We don't want to remove the search doc if there is a published version but a new draft has been created - const { - docs: [docWithPublish], - } = await payload.find({ - collection, - depth: 0, - draft: false, - limit: 1, - locale: syncLocale, - pagination: false, - req, - where: { - and: [ - { - _status: { - equals: 'published', - }, - }, - { - id: { - equals: id, - }, - }, - ], - }, - }) - - if (!docWithPublish && !isTrashDocument) { - // do not include draft docs in search results, so delete the record + } else { + if (doSync) { + // update the doc normally try { - await payload.delete({ + await payload.update({ id: searchDocID, collection: searchSlug, + data: { + ...dataToSave, + priority: foundDoc.priority || defaultPriority, + }, depth: 0, + locale: syncLocale, req, }) } catch (err: unknown) { - payload.logger.error({ err, msg: `Error deleting ${searchSlug} document.` }) + payload.logger.error({ err, msg: `Error updating ${searchSlug} document.` }) + } + } + + if (deleteDrafts && status === 'draft') { + // Check to see if there's a published version of the doc + // We don't want to remove the search doc if there is a published version but a new draft has been created + const { + docs: [docWithPublish], + } = await payload.find({ + collection, + depth: 0, + draft: false, + limit: 1, + locale: syncLocale, + pagination: false, + req, + where: { + and: [ + { + _status: { + equals: 'published', + }, + }, + { + id: { + equals: id, + }, + }, + ], + }, + }) + + if (!docWithPublish) { + // do not include draft docs in search results, so delete the record + try { + await payload.delete({ + id: searchDocID, + collection: searchSlug, + depth: 0, + req, + }) + } catch (err: unknown) { + payload.logger.error({ err, msg: `Error deleting ${searchSlug} document.` }) + } } } } diff --git a/test/_community/payload-types.ts b/test/_community/payload-types.ts index 8372cf69bbb..281c37c390a 100644 --- a/test/_community/payload-types.ts +++ b/test/_community/payload-types.ts @@ -86,7 +86,7 @@ export interface Config { 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; }; db: { - defaultIDType: string; + defaultIDType: number; }; fallbackLocale: null; globals: { @@ -127,7 +127,7 @@ export interface UserAuthOperations { * via the `definition` "posts". */ export interface Post { - id: string; + id: number; title?: string | null; content?: { root: { @@ -152,7 +152,7 @@ export interface Post { * via the `definition` "media". */ export interface Media { - id: string; + id: number; updatedAt: string; createdAt: string; url?: string | null; @@ -196,7 +196,7 @@ export interface Media { * via the `definition` "payload-kv". */ export interface PayloadKv { - id: string; + id: number; key: string; data: | { @@ -213,7 +213,7 @@ export interface PayloadKv { * via the `definition` "users". */ export interface User { - id: string; + id: number; updatedAt: string; createdAt: string; email: string; @@ -237,24 +237,24 @@ export interface User { * via the `definition` "payload-locked-documents". */ export interface PayloadLockedDocument { - id: string; + id: number; document?: | ({ relationTo: 'posts'; - value: string | Post; + value: number | Post; } | null) | ({ relationTo: 'media'; - value: string | Media; + value: number | Media; } | null) | ({ relationTo: 'users'; - value: string | User; + value: number | User; } | null); globalSlug?: string | null; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; updatedAt: string; createdAt: string; @@ -264,10 +264,10 @@ export interface PayloadLockedDocument { * via the `definition` "payload-preferences". */ export interface PayloadPreference { - id: string; + id: number; user: { relationTo: 'users'; - value: string | User; + value: number | User; }; key?: string | null; value?: @@ -287,7 +287,7 @@ export interface PayloadPreference { * via the `definition` "payload-migrations". */ export interface PayloadMigration { - id: string; + id: number; name?: string | null; batch?: number | null; updatedAt: string; @@ -421,7 +421,7 @@ export interface PayloadMigrationsSelect { * via the `definition` "menu". */ export interface Menu { - id: string; + id: number; globalText?: string | null; updatedAt?: string | null; createdAt?: string | null; diff --git a/test/plugin-search/config.ts b/test/plugin-search/config.ts index b77a214ec38..45d6394cc94 100644 --- a/test/plugin-search/config.ts +++ b/test/plugin-search/config.ts @@ -5,6 +5,8 @@ const dirname = path.dirname(filename) import { searchPlugin } from '@payloadcms/plugin-search' import { randomUUID } from 'node:crypto' +import type { Config } from './payload-types.js' + import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js' import { devUser } from '../credentials.js' import { Pages } from './collections/Pages.js' @@ -25,6 +27,20 @@ export default buildConfigWithDefaults({ slug: 'custom-ids-2', fields: [{ type: 'text', name: 'id' }], }, + { + slug: 'filtered-locales', + fields: [ + { + type: 'text', + name: 'title', + localized: true, + }, + { + type: 'checkbox', + name: 'syncEnglishOnly', + }, + ], + }, ], localization: { defaultLocale: 'en', @@ -48,7 +64,7 @@ export default buildConfigWithDefaults({ await seed(payload) }, plugins: [ - searchPlugin({ + searchPlugin({ beforeSync: ({ originalDoc, searchDoc }) => { return { ...searchDoc, @@ -56,7 +72,13 @@ export default buildConfigWithDefaults({ slug: originalDoc.slug, } }, - collections: ['pages', 'posts', 'custom-ids-1', 'custom-ids-2'], + collections: ['pages', 'posts', 'custom-ids-1', 'custom-ids-2', 'filtered-locales'], + skipSync: ({ locale, doc, collectionSlug }) => { + if (collectionSlug === 'filtered-locales' && doc.syncEnglishOnly) { + return locale !== 'en' + } + return false + }, defaultPriorities: { pages: 10, posts: ({ title }) => (title === 'Hello, world!' ? 30 : 20), diff --git a/test/plugin-search/int.spec.ts b/test/plugin-search/int.spec.ts index 06452edf116..89eb8683f58 100644 --- a/test/plugin-search/int.spec.ts +++ b/test/plugin-search/int.spec.ts @@ -734,4 +734,180 @@ describe('@payloadcms/plugin-search', () => { trash: true, // permanently delete }) }) + + describe('locale filtering', () => { + it('should filter locales when skipSync excludes them', async () => { + // Test config has 3 locales: ['en', 'es', 'de'] + // For 'filtered-locales' collection with syncEnglishOnly: true, only 'en' should be indexed + + // Create a doc with syncEnglishOnly enabled + const enDoc = await payload.create({ + collection: 'filtered-locales', + data: { + title: 'Filtered Doc', + syncEnglishOnly: true, + }, + locale: 'en', + }) + + // Query for ALL search docs with locale: 'all' to see total count + const { docs: allSearchDocs } = await payload.find({ + collection: 'search', + locale: 'all', + where: { + 'doc.value': { + equals: enDoc.id, + }, + }, + }) + + // Should only have 1 search doc total (English only) + expect(allSearchDocs).toHaveLength(1) + expect(allSearchDocs[0]?.doc.relationTo).toBe('filtered-locales') + + // Verify the search doc exists for English locale + const { docs } = await payload.find({ + collection: 'search', + locale: 'all', + where: { + 'doc.value': { + equals: enDoc.id, + }, + }, + }) + + expect(docs).toHaveLength(1) + + const doc = docs[0] + expect(doc).toBeDefined() + expect(doc.doc.relationTo).toBe('filtered-locales') + expect(doc.title).toHaveProperty('en', 'Filtered Doc') + expect(doc.title).not.toHaveProperty('es') + expect(doc.title).not.toHaveProperty('de') + + // Clean up + await payload.delete({ + collection: 'filtered-locales', + id: enDoc.id, + }) + }) + + it('should index all locales when skipSync allows all locales', async () => { + // Test config has 3 locales: ['en', 'es', 'de'] + // For 'posts' collection, skipSync returns false for all locales + + // Create a post + const post = await payload.create({ + collection: postsSlug, + data: { + _status: 'published', + title: 'Test Post for All Locales', + }, + locale: 'en', + }) + + // Update the post in Spanish locale + await payload.update({ + collection: postsSlug, + id: post.id, + locale: 'es', + data: { + _status: 'published', + title: 'Test Post para Todos los Locales', + }, + }) + + // Update the post in German locale + await payload.update({ + collection: postsSlug, + id: post.id, + locale: 'de', + data: { + _status: 'published', + title: 'Testbeitrag für alle Sprachen', + }, + }) + + // Query for search doc with locale: 'all' + const { docs: allSearchDocs } = await payload.find({ + collection: 'search', + locale: 'all', + where: { + 'doc.value': { + equals: post.id, + }, + }, + }) + + // Should have 1 search doc with all locales embedded + expect(allSearchDocs).toHaveLength(1) + expect(allSearchDocs[0]?.doc.relationTo).toBe(postsSlug) + // Verify all locales are present in the localized title field + expect(allSearchDocs[0]?.title).toHaveProperty('en', 'Test Post for All Locales') + expect(allSearchDocs[0]?.title).toHaveProperty('es', 'Test Post para Todos los Locales') + expect(allSearchDocs[0]?.title).toHaveProperty('de', 'Testbeitrag für alle Sprachen') + + // Clean up + await payload.delete({ + collection: postsSlug, + id: post.id, + }) + }) + + it('should index all locales when syncEnglishOnly is false', async () => { + // For 'filtered-locales' collection with syncEnglishOnly: false, all locales should be indexed + + // Create a doc with syncEnglishOnly disabled + const doc = await payload.create({ + collection: 'filtered-locales', + data: { + title: 'Unfiltered Doc', + syncEnglishOnly: false, + }, + locale: 'en', + }) + + // Verify search doc exists for English + const { docs: enSearchDocs } = await payload.find({ + collection: 'search', + locale: 'en', + where: { + 'doc.value': { + equals: doc.id, + }, + }, + }) + expect(enSearchDocs).toHaveLength(1) + + // Verify search doc exists for Spanish + const { docs: esSearchDocs } = await payload.find({ + collection: 'search', + locale: 'es', + where: { + 'doc.value': { + equals: doc.id, + }, + }, + }) + expect(esSearchDocs).toHaveLength(1) + + // Verify search doc exists for German + const { docs: deSearchDocs } = await payload.find({ + collection: 'search', + locale: 'de', + where: { + 'doc.value': { + equals: doc.id, + }, + }, + }) + expect(deSearchDocs).toHaveLength(1) + + // Clean up + await payload.delete({ + collection: 'filtered-locales', + id: doc.id, + }) + }) + }) }) diff --git a/test/plugin-search/payload-types.ts b/test/plugin-search/payload-types.ts index 9e5f3b6f816..7b93c97c151 100644 --- a/test/plugin-search/payload-types.ts +++ b/test/plugin-search/payload-types.ts @@ -72,7 +72,9 @@ export interface Config { posts: Post; 'custom-ids-1': CustomIds1; 'custom-ids-2': CustomIds2; + 'filtered-locales': FilteredLocale; search: Search; + 'payload-kv': PayloadKv; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; 'payload-migrations': PayloadMigration; @@ -84,7 +86,9 @@ export interface Config { posts: PostsSelect | PostsSelect; 'custom-ids-1': CustomIds1Select | CustomIds1Select; 'custom-ids-2': CustomIds2Select | CustomIds2Select; + 'filtered-locales': FilteredLocalesSelect | FilteredLocalesSelect; search: SearchSelect | SearchSelect; + 'payload-kv': PayloadKvSelect | PayloadKvSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; 'payload-migrations': PayloadMigrationsSelect | PayloadMigrationsSelect; @@ -92,6 +96,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: ('false' | 'none' | 'null') | false | null | ('en' | 'es' | 'de') | ('en' | 'es' | 'de')[]; globals: {}; globalsSelect: {}; locale: 'en' | 'es' | 'de'; @@ -153,6 +158,7 @@ export interface Page { id: string; title: string; excerpt?: string | null; + another?: string | null; updatedAt: string; createdAt: string; _status?: ('draft' | 'published') | null; @@ -189,6 +195,17 @@ export interface CustomIds2 { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "filtered-locales". + */ +export interface FilteredLocale { + id: string; + title?: string | null; + syncEnglishOnly?: boolean | null; + updatedAt: string; + createdAt: string; +} /** * This is a collection of automatically created search results. These results are used by the global site search and will be updated automatically as documents in the CMS are created or updated. * @@ -214,6 +231,10 @@ export interface Search { | { relationTo: 'custom-ids-2'; value: string | CustomIds2; + } + | { + relationTo: 'filtered-locales'; + value: string | FilteredLocale; }; id: string; excerpt?: string | null; @@ -221,6 +242,23 @@ export interface Search { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv". + */ +export interface PayloadKv { + id: string; + key: string; + data: + | { + [k: string]: unknown; + } + | unknown[] + | string + | number + | boolean + | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-locked-documents". @@ -248,6 +286,10 @@ export interface PayloadLockedDocument { relationTo: 'custom-ids-2'; value: string | CustomIds2; } | null) + | ({ + relationTo: 'filtered-locales'; + value: string | FilteredLocale; + } | null) | ({ relationTo: 'search'; value: string | Search; @@ -323,6 +365,7 @@ export interface UsersSelect { export interface PagesSelect { title?: T; excerpt?: T; + another?: T; updatedAt?: T; createdAt?: T; _status?: T; @@ -358,6 +401,16 @@ export interface CustomIds2Select { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "filtered-locales_select". + */ +export interface FilteredLocalesSelect { + title?: T; + syncEnglishOnly?: T; + updatedAt?: T; + createdAt?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "search_select". @@ -372,6 +425,14 @@ export interface SearchSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "payload-kv_select". + */ +export interface PayloadKvSelect { + key?: T; + data?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-locked-documents_select". From 2558b403958d536aa3ea05afa7adee5439867d62 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Tue, 6 Jan 2026 15:43:30 -0800 Subject: [PATCH 60/67] refactor: deprecate returning failed state from job queue handlers (#15102) This PR deprecates returning `{ state: 'failed' }`, which unnecessarily inflates the API. **Reasons:** - It duplicates existing behavior, making the API and docs more confusing. - It creates ambiguity about which approach developers should use. - It increases maintenance cost. - Throwing errors is more flexible: for example, cancelling a job from a task handler currently requires throwing `JobCancelledError`, which cannot be done via a return value. # Migration Example ## Before ```ts import type { TaskConfig } from 'payload' export const ReturnCustomErrorTask: TaskConfig<'ReturnCustomError'> = { retries: 0, slug: 'ReturnCustomError', inputSchema: [], outputSchema: [], handler: ({ input }) => { return { state: 'failed', errorMessage: 'oh no! this failed' } }, } ``` ## After ```ts import type { TaskConfig } from 'payload' export const ReturnCustomErrorTask: TaskConfig<'ReturnCustomError'> = { retries: 0, slug: 'ReturnCustomError', inputSchema: [], outputSchema: [], handler: ({ input }) => { throw new Error('oh no! this failed') }, } ``` --- .../payload/src/queues/config/types/taskTypes.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/payload/src/queues/config/types/taskTypes.ts b/packages/payload/src/queues/config/types/taskTypes.ts index 2ea90d4fe17..2f51b951b2d 100644 --- a/packages/payload/src/queues/config/types/taskTypes.ts +++ b/packages/payload/src/queues/config/types/taskTypes.ts @@ -10,7 +10,13 @@ export type TaskHandlerResult< TTaskSlugOrInputOutput extends keyof TypedJobs['tasks'] | TaskInputOutput, > = | { + /** + * @deprecated Returning `state: 'failed'` is deprecated. Throw an error instead. + */ errorMessage?: string + /** + * @deprecated Returning `state: 'failed'` is deprecated. Throw an error instead. + */ state: 'failed' } | { @@ -53,7 +59,7 @@ export type TaskHandler< TWorkflowSlug extends keyof TypedJobs['workflows'] = string, > = ( args: TaskHandlerArgs, -) => Promise> | TaskHandlerResult +) => MaybePromise> /** * @todo rename to TaskSlug in 4.0, similar to CollectionSlug @@ -116,7 +122,13 @@ export type RunInlineTaskFunction = MaybePromise< | { + /** + * @deprecated Returning `state: 'failed'` is deprecated. Throw an error instead. + */ errorMessage?: string + /** + * @deprecated Returning `state: 'failed'` is deprecated. Throw an error instead. + */ state: 'failed' } | { @@ -140,7 +152,7 @@ export type TaskCallbackArgs = { export type ShouldRestoreFn = ( args: { taskStatus: SingleTaskStatus } & Omit, ) => boolean | Promise -export type TaskCallbackFn = (args: TaskCallbackArgs) => Promise | void +export type TaskCallbackFn = (args: TaskCallbackArgs) => MaybePromise export type RetryConfig = { /** From 362aa50331864a1416d9201dfe81e13dd5024382 Mon Sep 17 00:00:00 2001 From: Ricardo Tavares Date: Wed, 7 Jan 2026 15:12:05 +0000 Subject: [PATCH 61/67] perf(graphql): optimized join count when docs are not needed (#14872) ### What? Optimizes the count of a join field when the goal is just to retrieve the count value (i.e. limit: 0). ### Why? Generates 1 database query instead of two when the goal is just to retrieve the count value. ### How? By using payload.count() instead of payload.find() Co-authored-by: Ricardo Tavares --- packages/graphql/src/schema/fieldToSchemaMap.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/graphql/src/schema/fieldToSchemaMap.ts b/packages/graphql/src/schema/fieldToSchemaMap.ts index 784c0a9ee9d..09976310125 100644 --- a/packages/graphql/src/schema/fieldToSchemaMap.ts +++ b/packages/graphql/src/schema/fieldToSchemaMap.ts @@ -444,6 +444,16 @@ export const fieldToSchemaMap: FieldToSchemaMap = { throw new Error('GraphQL with array of join.field.collection is not implemented') } + if (count && limit === 0) { + return await req.payload.count({ + collection, + depth: 0, + overrideAccess: false, + req, + where: fullWhere, + }) + } + const { docs, totalDocs } = await req.payload.find({ collection, depth: 0, From 1fdf98e35ac9178d5bf731af6835824807b4abab Mon Sep 17 00:00:00 2001 From: Patrik <35232443+PatrikKozak@users.noreply.github.com> Date: Wed, 7 Jan 2026 10:33:38 -0500 Subject: [PATCH 62/67] fix(ui): crop width and height inputs limited to -1 of max (#15101) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What Crop width/height inputs can now be incremented to the original image dimensions ### Why Users were unable to increment crop dimensions back to the full original size using arrow keys. The inputs would max out at `originalSize - 1`, even though typing the max value directly worked fine. ### How Removed redundant pixel-based validation in `fineTuneCrop` that was blocking state updates when dimensions equaled the original size. The percentage-based validation already handles invalid values (≤0% and >100%). Fixes #14758 --- packages/ui/src/elements/EditUpload/index.tsx | 8 +----- test/uploads/e2e.spec.ts | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/ui/src/elements/EditUpload/index.tsx b/packages/ui/src/elements/EditUpload/index.tsx index ba923f0cdd6..73197e15e3b 100644 --- a/packages/ui/src/elements/EditUpload/index.tsx +++ b/packages/ui/src/elements/EditUpload/index.tsx @@ -113,17 +113,11 @@ export const EditUpload: React.FC = ({ const fineTuneCrop = ({ dimension, value }: { dimension: 'height' | 'width'; value: string }) => { const intValue = parseInt(value) - if (dimension === 'width' && intValue >= uncroppedPixelWidth) { - return null - } - if (dimension === 'height' && intValue >= uncroppedPixelHeight) { - return null - } const percentage = 100 * (intValue / (dimension === 'width' ? uncroppedPixelWidth : uncroppedPixelHeight)) - if (percentage === 100 || percentage === 0) { + if (percentage <= 0 || percentage > 100) { return null } diff --git a/test/uploads/e2e.spec.ts b/test/uploads/e2e.spec.ts index 5adb4ec8227..dd562f2a8a4 100644 --- a/test/uploads/e2e.spec.ts +++ b/test/uploads/e2e.spec.ts @@ -1549,6 +1549,34 @@ describe('Uploads', () => { const resizeOptionMedia = page.locator('.file-meta .file-meta__size-type') await expect(resizeOptionMedia).toContainText('200x200') }) + + test('should allow incrementing crop dimensions back to original maximum size', async () => { + await page.goto(mediaURL.create) + + await page.setInputFiles('input[type="file"]', path.join(dirname, 'test-image.jpg')) + + await page.locator('.file-field__edit').click() + + const widthInput = page.locator('.edit-upload__input input[name="Width (px)"]') + const heightInput = page.locator('.edit-upload__input input[name="Height (px)"]') + + await expect(widthInput).toHaveValue('800') + await expect(heightInput).toHaveValue('800') + + await widthInput.fill('799') + await expect(widthInput).toHaveValue('799') + + // Increment back to original using arrow up + await widthInput.press('ArrowUp') + await expect(widthInput).toHaveValue('800') + + await heightInput.fill('799') + await expect(heightInput).toHaveValue('799') + + // Increment back to original using arrow up + await heightInput.press('ArrowUp') + await expect(heightInput).toHaveValue('800') + }) }) test('should see upload previews in relation list if allowed in config', async () => { From 809a10cd657d0bf6b9e2afad94aa9dce8da5be3f Mon Sep 17 00:00:00 2001 From: Ricardo Tavares Date: Wed, 7 Jan 2026 15:42:35 +0000 Subject: [PATCH 63/67] fix(templates): add recommended serverExternalPackages to cloudflare (#15094) ### What? Adds recommended serverExternalPackages to the Cloudflare template ### Why? To make packages with cloudflare-specific code work with OpenNext. More details here: https://opennext.js.org/cloudflare/howtos/workerd ### How? By adding the serverExternalPackages property to next.config.ts May fix #14656 Also helps when connecting to Postgres instead of D1 as mentioned in #14181 Co-authored-by: Ricardo Tavares --- templates/with-cloudflare-d1/next.config.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/templates/with-cloudflare-d1/next.config.ts b/templates/with-cloudflare-d1/next.config.ts index 762316ea40a..6857ab8b020 100644 --- a/templates/with-cloudflare-d1/next.config.ts +++ b/templates/with-cloudflare-d1/next.config.ts @@ -2,6 +2,10 @@ import { withPayload } from '@payloadcms/next/withPayload' /** @type {import('next').NextConfig} */ const nextConfig = { + // Packages with Cloudflare Workers (workerd) specific code + // Read more: https://opennext.js.org/cloudflare/howtos/workerd + serverExternalPackages: ['jose', 'pg-cloudflare'], + // Your Next.js config here webpack: (webpackConfig: any) => { webpackConfig.resolve.extensionAlias = { From dc420b15309a76d84b2d7d5482a6e8bbaba7e4f0 Mon Sep 17 00:00:00 2001 From: Ricardo Tavares Date: Wed, 7 Jan 2026 17:44:18 +0000 Subject: [PATCH 64/67] fix(templates): improve cli detection in cloudflare template (#15098) ### What? Improves the CLI detection in the Cloudflare template ### Why? To also support running scripts via `payload run` ### How? By looking for Payload's bin.js inside process.argv instead of just looking for the generate/migrate commands. Discord discussion: https://discord.com/channels/967097582721572934/1439728398405468291 Co-authored-by: Ricardo Tavares --- templates/with-cloudflare-d1/src/payload.config.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/templates/with-cloudflare-d1/src/payload.config.ts b/templates/with-cloudflare-d1/src/payload.config.ts index 21928b888fd..30333661f29 100644 --- a/templates/with-cloudflare-d1/src/payload.config.ts +++ b/templates/with-cloudflare-d1/src/payload.config.ts @@ -1,6 +1,7 @@ +import fs from 'fs' +import path from 'path' import { sqliteD1Adapter } from '@payloadcms/db-d1-sqlite' import { lexicalEditor } from '@payloadcms/richtext-lexical' -import path from 'path' import { buildConfig } from 'payload' import { fileURLToPath } from 'url' import { CloudflareContext, getCloudflareContext } from '@opennextjs/cloudflare' @@ -12,8 +13,9 @@ import { Media } from './collections/Media' const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) +const realpath = (value: string) => (fs.existsSync(value) ? fs.realpathSync(value) : undefined) -const isCLI = process.argv.some((value) => value.match(/^(generate|migrate):?/)) +const isCLI = process.argv.some((value) => realpath(value).endsWith(path.join('payload', 'bin.js'))) const isProduction = process.env.NODE_ENV === 'production' const cloudflare = From 497631918f5c38c772056ed274029e68aa2f3b35 Mon Sep 17 00:00:00 2001 From: Sean Zubrickas Date: Wed, 7 Jan 2026 16:11:58 -0500 Subject: [PATCH 65/67] docs: task failure docs (#15096) Updates documentation on how to properly fail a task. Fixes https://github.com/payloadcms/payload/issues/12050 Includes: - Two approaches to failing tasks (throw vs return failed state) - Examples with and without custom error messages - Guidance on when to use each approach - How to access failure information from job logs --- docs/jobs-queue/tasks.mdx | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/docs/jobs-queue/tasks.mdx b/docs/jobs-queue/tasks.mdx index d8c9034ceb5..c88c731d077 100644 --- a/docs/jobs-queue/tasks.mdx +++ b/docs/jobs-queue/tasks.mdx @@ -220,6 +220,77 @@ Sometimes you want to fail a task based on business logic: ``` +### Handling Task Failures + +Tasks fail by throwing errors. When a task encounters any type of failure—whether it's an unexpected error, a validation issue, or a business logic violation—you should throw an error with a descriptive message. + +```ts +handler: async ({ input, req }) => { + const order = await req.payload.findByID({ + collection: 'orders', + id: input.orderId, + }) + + // Validation failure + if (input.amount !== order.total) { + throw new Error( + `Amount mismatch: expected ${order.total}, received ${input.amount}`, + ) + } + + // Business rule failure + if (order.status === 'cancelled') { + throw new Error('Cannot process payment for cancelled order') + } + + // Conditional check + if (order.status === 'paid') { + throw new Error('Order already processed') + } + + // Continue processing... +} +``` + +#### Accessing Failure Information + +After a task fails, you can inspect the job to understand what went wrong: + +```ts +const job = await payload.jobs.queue({ + task: 'processPayment', + input: { orderId: '123', amount: 100 }, +}) + +// Run the job +await payload.jobs.run() + +// Check the job status +const completedJob = await payload.findByID({ + collection: 'payload-jobs', + id: job.id, +}) + +// Check if job failed +if (completedJob.hasError) { + // Access the latest error that caused the job to fail + console.log(completedJob.error) + // This will contain the error message from the thrown error + + // You can also check the job log to find specific tasks that errored + // Note: If the job was retried multiple times, there will be multiple erroring tasks in the log + const failedTasks = completedJob.log?.filter( + (entry) => entry.state === 'failed', + ) +} +``` + + + Always throw errors with descriptive messages for better debugging and + observability. The error message will be stored in the job's error field and + visible in the admin UI. + + ### Understanding Task Execution #### When a task runs From 54132aec65e4bfcbd78cf0fc4877987d097cf35c Mon Sep 17 00:00:00 2001 From: Jarrod Flesch <30633324+JarrodMFlesch@users.noreply.github.com> Date: Wed, 7 Jan 2026 16:34:17 -0500 Subject: [PATCH 66/67] test: fixes lexical block test flakes (#15113) Fixes the block/blockReferences tests that keep failing in CI. --- .../Lexical/e2e/blocks/e2e.spec.ts | 36 +++++++++++++------ test/lexical/payload-types.ts | 1 + 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/test/lexical/collections/Lexical/e2e/blocks/e2e.spec.ts b/test/lexical/collections/Lexical/e2e/blocks/e2e.spec.ts index 4d51c5356f0..06a00d45e64 100644 --- a/test/lexical/collections/Lexical/e2e/blocks/e2e.spec.ts +++ b/test/lexical/collections/Lexical/e2e/blocks/e2e.spec.ts @@ -59,11 +59,11 @@ describe('lexicalBlocks', () => { await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { - /*await throttleTest({ - page, - context, - delay: 'Slow 4G', - })*/ + // await throttleTest({ + // page, + // context, + // delay: 'Slow 4G', + // }) await reInitializeDB({ serverURL, snapshotKey: 'lexicalTest', @@ -101,20 +101,36 @@ describe('lexicalBlocks', () => { const editButton = newRSCBlock.locator('.LexicalEditorTheme__block__editButton').first() await editButton.click() - await wait(500) const editDrawer = page.locator('dialog[id^=drawer_1_lexical-blocks-create-]').first() // IDs starting with list-drawer_1_ (there's some other symbol after the underscore) await expect(editDrawer).toBeVisible() - await wait(500) await expect(page.locator('.shimmer-effect')).toHaveCount(0) await editDrawer.locator('.rs__control .value-container').first().click() await wait(500) await expect(editDrawer.locator('.rs__option').nth(1)).toBeVisible() await expect(editDrawer.locator('.rs__option').nth(1)).toContainText('value2') - await editDrawer.locator('.rs__option').nth(1).click() + await assertNetworkRequests( + page, + '/admin/collections/lexical-fields', + async () => { + await editDrawer.locator('.rs__option').nth(1).click() + }, + { + allowedNumberOfRequests: 2, + }, + ) // Click button with text Save changes - await editDrawer.locator('button').getByText('Save changes').click() + await assertNetworkRequests( + page, + '/admin/collections/lexical-fields', + async () => { + await editDrawer.locator('button').getByText('Save changes').click() + }, + { + allowedNumberOfRequests: 1, + }, + ) await expect(editDrawer).toBeHidden() await expect(newRSCBlock.locator('.collapsible__content')).toHaveText('Data: value2') @@ -1520,7 +1536,7 @@ async function navigateToLexicalFields( await expect(() => expect(linkToDoc).toBeTruthy()).toPass({ timeout: POLL_TOPASS_TIMEOUT }) const linkDocHref = await linkToDoc.getAttribute('href') - await linkToDoc.click() + await linkToDoc.click({ delay: 500 }) await page.waitForURL(`**${linkDocHref}`) diff --git a/test/lexical/payload-types.ts b/test/lexical/payload-types.ts index 2cb4d6ed924..5602b376c33 100644 --- a/test/lexical/payload-types.ts +++ b/test/lexical/payload-types.ts @@ -138,6 +138,7 @@ export interface Config { db: { defaultIDType: string; }; + fallbackLocale: ('false' | 'none' | 'null') | false | null | ('en' | 'es' | 'he') | ('en' | 'es' | 'he')[]; globals: { tabsWithRichText: TabsWithRichText; }; From c1c10dcc287a8ed09d9024d51fd6df2fabfd5b1e Mon Sep 17 00:00:00 2001 From: teastudiopl Date: Thu, 8 Jan 2026 20:53:37 +0100 Subject: [PATCH 67/67] Ecommerce Plugin - currency formatting and symbol positioning --- .../src/react/provider/index.tsx | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/packages/plugin-ecommerce/src/react/provider/index.tsx b/packages/plugin-ecommerce/src/react/provider/index.tsx index 3d0653b3f4c..26c2d5ed077 100644 --- a/packages/plugin-ecommerce/src/react/provider/index.tsx +++ b/packages/plugin-ecommerce/src/react/provider/index.tsx @@ -929,33 +929,22 @@ export const useCurrency = () => { const { currenciesConfig, currency, setCurrency } = useEcommerce() const formatCurrency = useCallback( - (value?: null | number, options?: { currency?: Currency }): string => { - if (value === undefined || value === null) { - return '' - } + (value?: null | number, options?: { currency?: Currency; locale?: string }): string => { + if (value === undefined || value === null) {return ''} const currencyToUse = options?.currency || currency + if (!currencyToUse) {return value.toString()} - if (!currencyToUse) { - return value.toString() - } - - const { decimals, symbol, symbolPosition = 'before', symbolSeparator = '' } = currencyToUse + const { code, decimals } = currencyToUse - // Convert from base value (e.g., cents) to decimal value (e.g., dollars) - const formattedNumber = - value === 0 - ? `0.${'0'.repeat(decimals)}` - : (value / Math.pow(10, decimals)).toFixed(decimals) - - if (!symbol) { - return formattedNumber - } + const locale = options?.locale || 'en' - // Format with the correct number of decimal places - return symbolPosition === 'before' - ? `${symbol}${symbolSeparator}${formattedNumber}` - : `${formattedNumber}${symbolSeparator}${symbol}` + return new Intl.NumberFormat(locale, { + currency: code, + maximumFractionDigits: decimals, + minimumFractionDigits: decimals, + style: 'currency', + }).format(value / Math.pow(10, decimals)) }, [currency], )