Compare commits
6 Commits
perf/initr
...
fix/checkD
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
764c42eb80 | ||
|
|
7626ff4635 | ||
|
|
9595e74153 | ||
|
|
58243a20e2 | ||
|
|
a62d86fd15 | ||
|
|
0a664f9bac |
@@ -1054,13 +1054,13 @@ import { usePayloadAPI } from '@payloadcms/ui'
|
||||
|
||||
const MyComponent: React.FC = () => {
|
||||
// Fetch data from a collection item using its ID
|
||||
const [{ data, isError, isLoading }, { setParams }] = usePayloadAPI(
|
||||
const [{ data, error, isLoading }, { setParams }] = usePayloadAPI(
|
||||
'/api/posts/123',
|
||||
{ initialParams: { depth: 1 } }
|
||||
)
|
||||
|
||||
if (isLoading) return <p>Loading...</p>
|
||||
if (isError) return <p>Error occurred while fetching data.</p>
|
||||
if (error) return <p>Error: {error.message}</p>
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -1094,7 +1094,7 @@ The first item in the returned array is an object containing the following prope
|
||||
| Property | Description |
|
||||
| --------------- | -------------------------------------------------------- |
|
||||
| **`data`** | The API response data. |
|
||||
| **`isError`** | A boolean indicating whether the request failed. |
|
||||
| **`error`** | If an error occurs, this contains the error object. |
|
||||
| **`isLoading`** | A boolean indicating whether the request is in progress. |
|
||||
|
||||
The second item is an object with the following methods:
|
||||
|
||||
@@ -63,41 +63,42 @@ export default buildConfig({
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Option | Description |
|
||||
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). |
|
||||
| **`bin`** | Register custom bin scripts for Payload to execute. [More Details](#custom-bin-scripts). |
|
||||
| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). |
|
||||
| **`db`** * | The Database Adapter which will be used by Payload. [More details](../database/overview). |
|
||||
| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. |
|
||||
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
|
||||
| **`compatibility`** | Compatibility flags for earlier versions of Payload. [More details](#compatibility-flags). |
|
||||
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
|
||||
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cors). |
|
||||
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
|
||||
| **`logger`** | Logger options, logger options with a destination stream, or an instantiated logger instance. [More details](https://getpino.io/#/docs/api?id=options). |
|
||||
| **`loggingLevels`** | An object to override the level to use in the logger for Payload's errors. |
|
||||
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
|
||||
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
|
||||
| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/cookies#csrf-attacks). |
|
||||
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). |
|
||||
| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. |
|
||||
| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). |
|
||||
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
|
||||
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
|
||||
| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). |
|
||||
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
|
||||
| **`onInit`** | A function that is called immediately following startup that receives the Payload instance as its only argument. |
|
||||
| **`debug`** | Enable to expose more detailed error information. |
|
||||
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
|
||||
| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). |
|
||||
| **`plugins`** | An array of Plugins. [More details](../plugins/overview). |
|
||||
| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
|
||||
| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). |
|
||||
| **`secret`** * | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. |
|
||||
| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. |
|
||||
| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). |
|
||||
| Option | Description |
|
||||
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). |
|
||||
| **`bin`** | Register custom bin scripts for Payload to execute. |
|
||||
| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). |
|
||||
| **`db`** * | The Database Adapter which will be used by Payload. [More details](../database/overview). |
|
||||
| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. |
|
||||
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
|
||||
| **`compatibility`** | Compatibility flags for earlier versions of Payload. [More details](#compatibility-flags). |
|
||||
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
|
||||
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cors). |
|
||||
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
|
||||
| **`logger`** | Logger options, logger options with a destination stream, or an instantiated logger instance. [More details](https://getpino.io/#/docs/api?id=options). |
|
||||
| **`loggingLevels`** | An object to override the level to use in the logger for Payload's errors. |
|
||||
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
|
||||
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
|
||||
| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/cookies#csrf-attacks). |
|
||||
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). |
|
||||
| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. |
|
||||
| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). |
|
||||
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
|
||||
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
|
||||
| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). |
|
||||
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
|
||||
| **`onInit`** | A function that is called immediately following startup that receives the Payload instance as its only argument. |
|
||||
| **`debug`** | Enable to expose more detailed error information. |
|
||||
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
|
||||
| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). |
|
||||
| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). |
|
||||
| **`plugins`** | An array of Plugins. [More details](../plugins/overview). |
|
||||
| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
|
||||
| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). |
|
||||
| **`secret`** * | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. |
|
||||
| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. |
|
||||
| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). |
|
||||
|
||||
_* An asterisk denotes that a property is required._
|
||||
|
||||
@@ -265,43 +266,3 @@ The Payload Config can accept compatibility flags for running the newest version
|
||||
Payload localization works on a field-by-field basis. As you can nest fields within other fields, you could potentially nest a localized field within a localized field—but this would be redundant and unnecessary. There would be no reason to define a localized field within a localized parent field, given that the entire data structure from the parent field onward would be localized.
|
||||
|
||||
By default, Payload will remove the `localized: true` property from sub-fields if a parent field is localized. Set this compatibility flag to `true` only if you have an existing Payload MongoDB database from pre-3.0, and you have nested localized fields that you would like to maintain without migrating.
|
||||
|
||||
|
||||
## Custom bin scripts
|
||||
|
||||
Using the `bin` configuration property, you can inject your own scripts to `npx payload`.
|
||||
Example for `pnpm payload seed`:
|
||||
|
||||
|
||||
Step 1: create `seed.ts` file in the same folder with `payload.config.ts` with:
|
||||
|
||||
```ts
|
||||
import type { SanitizedConfig } from 'payload'
|
||||
|
||||
import payload from 'payload'
|
||||
|
||||
// Script must define a "script" function export that accepts the sanitized config
|
||||
export const script = async (config: SanitizedConfig) => {
|
||||
await payload.init({ config })
|
||||
await payload.create({ collection: 'pages', data: { title: 'my title' } })
|
||||
payload.logger.info('Succesffully seeded!')
|
||||
process.exit(0)
|
||||
}
|
||||
```
|
||||
|
||||
Step 2: add the `seed` script to `bin`:
|
||||
```ts
|
||||
export default buildConfig({
|
||||
bin: [
|
||||
{
|
||||
scriptPath: path.resolve(dirname, 'seed.ts'),
|
||||
key: 'seed',
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Now you can run the command using:
|
||||
```sh
|
||||
pnpm payload seed
|
||||
```
|
||||
@@ -276,7 +276,7 @@ export default async function MyServerComponent({
|
||||
|
||||
But, the Payload Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types) by design. It is full of custom validation functions and more. This means that the Payload Config, in its entirety, cannot be passed directly to Client Components.
|
||||
|
||||
For this reason, Payload creates a Client Config and passes it into the Config Provider. This is a serializable version of the Payload Config that can be accessed from any Client Component via the [`useConfig`](../admin/react-hooks#useconfig) hook:
|
||||
For this reason, Payload creates a Client Config and passes it into the Config Provider. This is a serializable version of the Payload Config that can be accessed from any Client Component via the [`useConfig`](../admin/hooks#useconfig) hook:
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
@@ -375,7 +375,7 @@ export function MyClientComponent() {
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
See the [Hooks](../admin/react-hooks) documentation for a full list of available hooks.
|
||||
See the [Hooks](../admin/hooks) documentation for a full list of available hooks.
|
||||
</Banner>
|
||||
|
||||
### Getting the Current Locale
|
||||
@@ -422,12 +422,12 @@ function Greeting() {
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
See the [Hooks](../admin/react-hooks) documentation for a full list of available hooks.
|
||||
See the [Hooks](../admin/hooks) documentation for a full list of available hooks.
|
||||
</Banner>
|
||||
|
||||
### Using Hooks
|
||||
|
||||
To make it easier to [build your Custom Components](#building-custom-components), you can use [Payload's built-in React Hooks](../admin/react-hooks) in any Client Component. For example, you might want to interact with one of Payload's many React Contexts. To do this, you can use one of the many hooks available depending on your needs.
|
||||
To make it easier to [build your Custom Components](#building-custom-components), you can use [Payload's built-in React Hooks](../admin/hooks) in any Client Component. For example, you might want to interact with one of Payload's many React Contexts. To do this, you can use one of the many hooks available depending on your needs.
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
@@ -444,7 +444,7 @@ export function MyClientComponent() {
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
See the [Hooks](../admin/react-hooks) documentation for a full list of available hooks.
|
||||
See the [Hooks](../admin/hooks) documentation for a full list of available hooks.
|
||||
</Banner>
|
||||
|
||||
### Adding Styles
|
||||
|
||||
@@ -79,11 +79,10 @@ export const MyBlocksField: Field = {
|
||||
|
||||
The Blocks Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | -------------------------------------------------------------------------- |
|
||||
| **`group`** | Text or localization object used to group this Block in the Blocks Drawer. |
|
||||
| **`initCollapsed`** | Set the initial collapsed state |
|
||||
| **`isSortable`** | Disable order sorting by setting this value to `false` |
|
||||
| Option | Description |
|
||||
| ------------------- | ---------------------------------- |
|
||||
| **`initCollapsed`** | Set the initial collapsed state |
|
||||
| **`isSortable`** | Disable order sorting by setting this value to `false` |
|
||||
|
||||
#### Customizing the way your block is rendered in Lexical
|
||||
|
||||
|
||||
@@ -239,9 +239,7 @@ This will add a dropdown to the date picker that allows users to select a timezo
|
||||
|
||||
You can customise the available list of timezones in the [global admin config](../admin/overview#timezones).
|
||||
|
||||
<Banner type="info">
|
||||
<Banner type='info'>
|
||||
**Good to know:**
|
||||
The date itself will be stored in UTC so it's up to you to handle the conversion to the user's timezone when displaying the date in your frontend.
|
||||
|
||||
Dates without a specific time are normalised to 12:00 in the selected timezone.
|
||||
</Banner>
|
||||
|
||||
@@ -658,7 +658,7 @@ In addition to the above props, all Server Components will also receive the foll
|
||||
|
||||
When swapping out the `Field` component, you are responsible for sending and receiving the field's `value` from the form itself.
|
||||
|
||||
To do so, import the [`useField`](../admin/react-hooks#usefield) hook from `@payloadcms/ui` and use it to manage the field's value:
|
||||
To do so, import the [`useField`](../admin/hooks#usefield) hook from `@payloadcms/ui` and use it to manage the field's value:
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
@@ -677,7 +677,7 @@ export const CustomTextField: React.FC = () => {
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
For a complete list of all available React hooks, see the [Payload React Hooks](../admin/react-hooks) documentation. For additional help, see [Building Custom Components](../custom-components/overview#building-custom-components).
|
||||
For a complete list of all available React hooks, see the [Payload React Hooks](../admin/hooks) documentation. For additional help, see [Building Custom Components](../custom-components/overview#building-custom-components).
|
||||
</Banner>
|
||||
|
||||
##### TypeScript#field-component-types
|
||||
|
||||
@@ -50,7 +50,6 @@ export const MyRadioField: Field = {
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`enumName`** | Custom enum name for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
|
||||
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ export const MySelectField: Field = {
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`enumName`** | Custom enum name for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`dbName`** | Custom table name (if `hasMany` set to `true`) for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
|
||||
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
|
||||
|
||||
|
||||
@@ -71,7 +71,8 @@ The following arguments are provided to all Field Hooks:
|
||||
| **`schemaPath`** | The path of the [Field](../fields/overview) in the schema. |
|
||||
| **`siblingData`** | The data of sibling fields adjacent to the field that the Hook is running against. |
|
||||
| **`siblingDocWithLocales`** | The sibling data of the Document with all [Locales](../configuration/localization). |
|
||||
| **`siblingFields`** | The sibling fields of the field which the hook is running against. |
|
||||
| **`siblingFields`** | The sibling fields of the field which the hook is running against.
|
||||
|
|
||||
| **`value`** | The value of the [Field](../fields/overview). |
|
||||
|
||||
<Banner type="success">
|
||||
|
||||
@@ -27,7 +27,7 @@ There are four main types of Hooks in Payload:
|
||||
|
||||
<Banner type="warning">
|
||||
**Reminder:**
|
||||
Payload also ships a set of _React_ hooks that you can use in your frontend application. Although they share a common name, these are very different things and should not be confused. [More details](../admin/react-hooks).
|
||||
Payload also ships a set of _React_ hooks that you can use in your frontend application. Although they share a common name, these are very different things and should not be confused. [More details](../admin/hooks).
|
||||
</Banner>
|
||||
|
||||
## Root Hooks
|
||||
|
||||
@@ -256,14 +256,18 @@ If you are using relationships or uploads in your front-end application, and you
|
||||
// ...
|
||||
// If your site is running on a different domain than your Payload server,
|
||||
// This will allows requests to be made between the two domains
|
||||
cors: [
|
||||
'http://localhost:3001' // Your front-end application
|
||||
],
|
||||
cors: {
|
||||
[
|
||||
'http://localhost:3001' // Your front-end application
|
||||
],
|
||||
},
|
||||
// If you are protecting resources behind user authentication,
|
||||
// This will allow cookies to be sent between the two domains
|
||||
csrf: [
|
||||
'http://localhost:3001' // Your front-end application
|
||||
],
|
||||
csrf: {
|
||||
[
|
||||
'http://localhost:3001' // Your front-end application
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -145,13 +145,13 @@ Here's an overview of all the included features:
|
||||
|
||||
| Feature Name | Included by default | Description |
|
||||
| --- | --- | --- |
|
||||
| **`BoldFeature`** | Yes | Handles the bold text format |
|
||||
| **`ItalicFeature`** | Yes | Handles the italic text format |
|
||||
| **`UnderlineFeature`** | Yes | Handles the underline text format |
|
||||
| **`StrikethroughFeature`** | Yes | Handles the strikethrough text format |
|
||||
| **`SubscriptFeature`** | Yes | Handles the subscript text format |
|
||||
| **`SuperscriptFeature`** | Yes | Handles the superscript text format |
|
||||
| **`InlineCodeFeature`** | Yes | Handles the inline-code text format |
|
||||
| **`BoldTextFeature`** | Yes | Handles the bold text format |
|
||||
| **`ItalicTextFeature`** | Yes | Handles the italic text format |
|
||||
| **`UnderlineTextFeature`** | Yes | Handles the underline text format |
|
||||
| **`StrikethroughTextFeature`** | Yes | Handles the strikethrough text format |
|
||||
| **`SubscriptTextFeature`** | Yes | Handles the subscript text format |
|
||||
| **`SuperscriptTextFeature`** | Yes | Handles the superscript text format |
|
||||
| **`InlineCodeTextFeature`** | Yes | Handles the inline-code text format |
|
||||
| **`ParagraphFeature`** | Yes | Handles paragraphs. Since they are already a key feature of lexical itself, this Feature mainly handles the Slash and Add-Block menu entries for paragraphs |
|
||||
| **`HeadingFeature`** | Yes | Adds Heading Nodes (by default, H1 - H6, but that can be customized) |
|
||||
| **`AlignFeature`** | Yes | Allows you to align text left, centered and right |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload-monorepo",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-payload-app",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-mongodb",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "The officially supported MongoDB database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { MongooseAdapter } from './index.js'
|
||||
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { handleError } from './utilities/handleError.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeRelationshipIDs } from './utilities/sanitizeRelationshipIDs.js'
|
||||
|
||||
export const create: Create = async function create(
|
||||
this: MongooseAdapter,
|
||||
@@ -18,31 +18,31 @@ export const create: Create = async function create(
|
||||
|
||||
let doc
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
const sanitizedData = sanitizeRelationshipIDs({
|
||||
config: this.payload.config,
|
||||
data,
|
||||
fields: this.payload.collections[collection].config.fields,
|
||||
operation: 'write',
|
||||
})
|
||||
|
||||
if (this.payload.collections[collection].customIDType) {
|
||||
data._id = data.id
|
||||
sanitizedData._id = sanitizedData.id
|
||||
}
|
||||
|
||||
try {
|
||||
;[doc] = await Model.create([data], options)
|
||||
;[doc] = await Model.create([sanitizedData], options)
|
||||
} catch (error) {
|
||||
handleError({ collection, error, req })
|
||||
}
|
||||
|
||||
doc = doc.toObject()
|
||||
// doc.toJSON does not do stuff like converting ObjectIds to string, or date strings to date objects. That's why we use JSON.parse/stringify here
|
||||
const result: Document = JSON.parse(JSON.stringify(doc))
|
||||
const verificationToken = doc._verificationToken
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data: doc,
|
||||
fields: this.payload.collections[collection].config.fields,
|
||||
operation: 'read',
|
||||
})
|
||||
// custom id type reset
|
||||
result.id = result._id
|
||||
if (verificationToken) {
|
||||
result._verificationToken = verificationToken
|
||||
}
|
||||
|
||||
return doc
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import type { CreateGlobal } from 'payload'
|
||||
import type { MongooseAdapter } from './index.js'
|
||||
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||
import { sanitizeRelationshipIDs } from './utilities/sanitizeRelationshipIDs.js'
|
||||
|
||||
export const createGlobal: CreateGlobal = async function createGlobal(
|
||||
this: MongooseAdapter,
|
||||
@@ -12,28 +13,26 @@ export const createGlobal: CreateGlobal = async function createGlobal(
|
||||
) {
|
||||
const Model = this.globals
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data,
|
||||
const global = sanitizeRelationshipIDs({
|
||||
config: this.payload.config,
|
||||
data: {
|
||||
globalType: slug,
|
||||
...data,
|
||||
},
|
||||
fields: this.payload.config.globals.find((globalConfig) => globalConfig.slug === slug).fields,
|
||||
globalSlug: slug,
|
||||
operation: 'write',
|
||||
})
|
||||
|
||||
const options: CreateOptions = {
|
||||
session: await getSession(this, req),
|
||||
}
|
||||
|
||||
let [result] = (await Model.create([data], options)) as any
|
||||
let [result] = (await Model.create([global], options)) as any
|
||||
|
||||
result = result.toObject()
|
||||
result = JSON.parse(JSON.stringify(result))
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data: result,
|
||||
fields: this.payload.config.globals.find((globalConfig) => globalConfig.slug === slug).fields,
|
||||
operation: 'read',
|
||||
})
|
||||
// custom id type reset
|
||||
result.id = result._id
|
||||
result = sanitizeInternalFields(result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { CreateOptions } from 'mongoose'
|
||||
|
||||
import { buildVersionGlobalFields, type CreateGlobalVersion } from 'payload'
|
||||
import { buildVersionGlobalFields, type CreateGlobalVersion, type Document } from 'payload'
|
||||
|
||||
import type { MongooseAdapter } from './index.js'
|
||||
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeRelationshipIDs } from './utilities/sanitizeRelationshipIDs.js'
|
||||
|
||||
export const createGlobalVersion: CreateGlobalVersion = async function createGlobalVersion(
|
||||
this: MongooseAdapter,
|
||||
@@ -26,30 +26,25 @@ export const createGlobalVersion: CreateGlobalVersion = async function createGlo
|
||||
session: await getSession(this, req),
|
||||
}
|
||||
|
||||
const data = {
|
||||
autosave,
|
||||
createdAt,
|
||||
latest: true,
|
||||
parent,
|
||||
publishedLocale,
|
||||
snapshot,
|
||||
updatedAt,
|
||||
version: versionData,
|
||||
}
|
||||
|
||||
const fields = buildVersionGlobalFields(
|
||||
this.payload.config,
|
||||
this.payload.config.globals.find((global) => global.slug === globalSlug),
|
||||
)
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data,
|
||||
fields,
|
||||
operation: 'write',
|
||||
const data = sanitizeRelationshipIDs({
|
||||
config: this.payload.config,
|
||||
data: {
|
||||
autosave,
|
||||
createdAt,
|
||||
latest: true,
|
||||
parent,
|
||||
publishedLocale,
|
||||
snapshot,
|
||||
updatedAt,
|
||||
version: versionData,
|
||||
},
|
||||
fields: buildVersionGlobalFields(
|
||||
this.payload.config,
|
||||
this.payload.config.globals.find((global) => global.slug === globalSlug),
|
||||
),
|
||||
})
|
||||
|
||||
let [doc] = await VersionModel.create([data], options, req)
|
||||
const [doc] = await VersionModel.create([data], options, req)
|
||||
|
||||
await VersionModel.updateMany(
|
||||
{
|
||||
@@ -75,14 +70,13 @@ export const createGlobalVersion: CreateGlobalVersion = async function createGlo
|
||||
options,
|
||||
)
|
||||
|
||||
doc = doc.toObject()
|
||||
const result: Document = JSON.parse(JSON.stringify(doc))
|
||||
const verificationToken = doc._verificationToken
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data: doc,
|
||||
fields,
|
||||
operation: 'read',
|
||||
})
|
||||
|
||||
return doc
|
||||
// custom id type reset
|
||||
result.id = result._id
|
||||
if (verificationToken) {
|
||||
result._verificationToken = verificationToken
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import type { CreateOptions } from 'mongoose'
|
||||
|
||||
import { buildVersionCollectionFields, type CreateVersion } from 'payload'
|
||||
import { Types } from 'mongoose'
|
||||
import { buildVersionCollectionFields, type CreateVersion, type Document } from 'payload'
|
||||
|
||||
import type { MongooseAdapter } from './index.js'
|
||||
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeRelationshipIDs } from './utilities/sanitizeRelationshipIDs.js'
|
||||
|
||||
export const createVersion: CreateVersion = async function createVersion(
|
||||
this: MongooseAdapter,
|
||||
@@ -26,30 +27,25 @@ export const createVersion: CreateVersion = async function createVersion(
|
||||
session: await getSession(this, req),
|
||||
}
|
||||
|
||||
const data = {
|
||||
autosave,
|
||||
createdAt,
|
||||
latest: true,
|
||||
parent,
|
||||
publishedLocale,
|
||||
snapshot,
|
||||
updatedAt,
|
||||
version: versionData,
|
||||
}
|
||||
|
||||
const fields = buildVersionCollectionFields(
|
||||
this.payload.config,
|
||||
this.payload.collections[collectionSlug].config,
|
||||
)
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data,
|
||||
fields,
|
||||
operation: 'write',
|
||||
const data = sanitizeRelationshipIDs({
|
||||
config: this.payload.config,
|
||||
data: {
|
||||
autosave,
|
||||
createdAt,
|
||||
latest: true,
|
||||
parent,
|
||||
publishedLocale,
|
||||
snapshot,
|
||||
updatedAt,
|
||||
version: versionData,
|
||||
},
|
||||
fields: buildVersionCollectionFields(
|
||||
this.payload.config,
|
||||
this.payload.collections[collectionSlug].config,
|
||||
),
|
||||
})
|
||||
|
||||
let [doc] = await VersionModel.create([data], options, req)
|
||||
const [doc] = await VersionModel.create([data], options, req)
|
||||
|
||||
const parentQuery = {
|
||||
$or: [
|
||||
@@ -60,6 +56,13 @@ export const createVersion: CreateVersion = async function createVersion(
|
||||
},
|
||||
],
|
||||
}
|
||||
if (data.parent instanceof Types.ObjectId) {
|
||||
parentQuery.$or.push({
|
||||
parent: {
|
||||
$eq: data.parent.toString(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
await VersionModel.updateMany(
|
||||
{
|
||||
@@ -86,14 +89,13 @@ export const createVersion: CreateVersion = async function createVersion(
|
||||
options,
|
||||
)
|
||||
|
||||
doc = doc.toObject()
|
||||
const result: Document = JSON.parse(JSON.stringify(doc))
|
||||
const verificationToken = doc._verificationToken
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data: doc,
|
||||
fields,
|
||||
operation: 'read',
|
||||
})
|
||||
|
||||
return doc
|
||||
// custom id type reset
|
||||
result.id = result._id
|
||||
if (verificationToken) {
|
||||
result._verificationToken = verificationToken
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { QueryOptions } from 'mongoose'
|
||||
import type { DeleteOne } from 'payload'
|
||||
import type { DeleteOne, Document } from 'payload'
|
||||
|
||||
import type { MongooseAdapter } from './index.js'
|
||||
|
||||
import { buildQuery } from './queries/buildQuery.js'
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||
|
||||
export const deleteOne: DeleteOne = async function deleteOne(
|
||||
this: MongooseAdapter,
|
||||
@@ -35,12 +35,11 @@ export const deleteOne: DeleteOne = async function deleteOne(
|
||||
return null
|
||||
}
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data: doc,
|
||||
fields: this.payload.collections[collection].config.fields,
|
||||
operation: 'read',
|
||||
})
|
||||
let result: Document = JSON.parse(JSON.stringify(doc))
|
||||
|
||||
return doc
|
||||
// custom id type reset
|
||||
result.id = result._id
|
||||
result = sanitizeInternalFields(result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import { buildSortParam } from './queries/buildSortParam.js'
|
||||
import { buildJoinAggregation } from './utilities/buildJoinAggregation.js'
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||
|
||||
export const find: Find = async function find(
|
||||
this: MongooseAdapter,
|
||||
@@ -133,12 +133,13 @@ export const find: Find = async function find(
|
||||
result = await Model.paginate(query, paginationOptions)
|
||||
}
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data: result.docs,
|
||||
fields: this.payload.collections[collection].config.fields,
|
||||
operation: 'read',
|
||||
})
|
||||
const docs = JSON.parse(JSON.stringify(result.docs))
|
||||
|
||||
return result
|
||||
return {
|
||||
...result,
|
||||
docs: docs.map((doc) => {
|
||||
doc.id = doc._id
|
||||
return sanitizeInternalFields(doc)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,14 @@ import type { MongooseAdapter } from './index.js'
|
||||
import { buildQuery } from './queries/buildQuery.js'
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||
|
||||
export const findGlobal: FindGlobal = async function findGlobal(
|
||||
this: MongooseAdapter,
|
||||
{ slug, locale, req, select, where },
|
||||
) {
|
||||
const Model = this.globals
|
||||
const globalConfig = this.payload.globals.config.find((each) => each.slug === slug)
|
||||
const fields = globalConfig.flattenedFields
|
||||
const fields = this.payload.globals.config.find((each) => each.slug === slug).flattenedFields
|
||||
const options: QueryOptions = {
|
||||
lean: true,
|
||||
select: buildProjectionFromSelect({
|
||||
@@ -35,18 +34,18 @@ export const findGlobal: FindGlobal = async function findGlobal(
|
||||
where: combineQueries({ globalType: { equals: slug } }, where),
|
||||
})
|
||||
|
||||
const doc = (await Model.findOne(query, {}, options)) as any
|
||||
let doc = (await Model.findOne(query, {}, options)) as any
|
||||
|
||||
if (!doc) {
|
||||
return null
|
||||
}
|
||||
if (doc._id) {
|
||||
doc.id = doc._id
|
||||
delete doc._id
|
||||
}
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data: doc,
|
||||
fields: globalConfig.fields,
|
||||
operation: 'read',
|
||||
})
|
||||
doc = JSON.parse(JSON.stringify(doc))
|
||||
doc = sanitizeInternalFields(doc)
|
||||
|
||||
return doc
|
||||
}
|
||||
|
||||
@@ -9,15 +9,18 @@ import { buildQuery } from './queries/buildQuery.js'
|
||||
import { buildSortParam } from './queries/buildSortParam.js'
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||
|
||||
export const findGlobalVersions: FindGlobalVersions = async function findGlobalVersions(
|
||||
this: MongooseAdapter,
|
||||
{ global, limit, locale, page, pagination, req, select, skip, sort: sortArg, where },
|
||||
) {
|
||||
const globalConfig = this.payload.globals.config.find(({ slug }) => slug === global)
|
||||
const Model = this.versions[global]
|
||||
const versionFields = buildVersionGlobalFields(this.payload.config, globalConfig, true)
|
||||
const versionFields = buildVersionGlobalFields(
|
||||
this.payload.config,
|
||||
this.payload.globals.config.find(({ slug }) => slug === global),
|
||||
true,
|
||||
)
|
||||
|
||||
const session = await getSession(this, req)
|
||||
const options: QueryOptions = {
|
||||
@@ -100,13 +103,13 @@ export const findGlobalVersions: FindGlobalVersions = async function findGlobalV
|
||||
}
|
||||
|
||||
const result = await Model.paginate(query, paginationOptions)
|
||||
const docs = JSON.parse(JSON.stringify(result.docs))
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data: result.docs,
|
||||
fields: buildVersionGlobalFields(this.payload.config, globalConfig),
|
||||
operation: 'read',
|
||||
})
|
||||
|
||||
return result
|
||||
return {
|
||||
...result,
|
||||
docs: docs.map((doc) => {
|
||||
doc.id = doc._id
|
||||
return sanitizeInternalFields(doc)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { AggregateOptions, QueryOptions } from 'mongoose'
|
||||
import type { FindOne } from 'payload'
|
||||
import type { Document, FindOne } from 'payload'
|
||||
|
||||
import type { MongooseAdapter } from './index.js'
|
||||
|
||||
@@ -7,7 +7,7 @@ import { buildQuery } from './queries/buildQuery.js'
|
||||
import { buildJoinAggregation } from './utilities/buildJoinAggregation.js'
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||
|
||||
export const findOne: FindOne = async function findOne(
|
||||
this: MongooseAdapter,
|
||||
@@ -58,7 +58,11 @@ export const findOne: FindOne = async function findOne(
|
||||
return null
|
||||
}
|
||||
|
||||
transform({ adapter: this, data: doc, fields: collectionConfig.fields, operation: 'read' })
|
||||
let result: Document = JSON.parse(JSON.stringify(doc))
|
||||
|
||||
return doc
|
||||
// custom id type reset
|
||||
result.id = result._id
|
||||
result = sanitizeInternalFields(result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { buildQuery } from './queries/buildQuery.js'
|
||||
import { buildSortParam } from './queries/buildSortParam.js'
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||
|
||||
export const findVersions: FindVersions = async function findVersions(
|
||||
this: MongooseAdapter,
|
||||
@@ -104,13 +104,13 @@ export const findVersions: FindVersions = async function findVersions(
|
||||
}
|
||||
|
||||
const result = await Model.paginate(query, paginationOptions)
|
||||
const docs = JSON.parse(JSON.stringify(result.docs))
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data: result.docs,
|
||||
fields: buildVersionCollectionFields(this.payload.config, collectionConfig),
|
||||
operation: 'read',
|
||||
})
|
||||
|
||||
return result
|
||||
return {
|
||||
...result,
|
||||
docs: docs.map((doc) => {
|
||||
doc.id = doc._id
|
||||
return sanitizeInternalFields(doc)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,7 +476,6 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
|
||||
if (fieldShouldBeLocalized({ field, parentIsLocalized }) && payload.config.localization) {
|
||||
schemaToReturn = {
|
||||
_id: false,
|
||||
type: payload.config.localization.localeCodes.reduce((locales, locale) => {
|
||||
let localeSchema: { [key: string]: any } = {}
|
||||
|
||||
@@ -699,7 +698,6 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
|
||||
if (fieldShouldBeLocalized({ field, parentIsLocalized }) && payload.config.localization) {
|
||||
schemaToReturn = {
|
||||
_id: false,
|
||||
type: payload.config.localization.localeCodes.reduce((locales, locale) => {
|
||||
let localeSchema: { [key: string]: any } = {}
|
||||
|
||||
|
||||
@@ -6,12 +6,11 @@ import { buildVersionCollectionFields, buildVersionGlobalFields } from 'payload'
|
||||
import type { MongooseAdapter } from '../index.js'
|
||||
|
||||
import { getSession } from '../utilities/getSession.js'
|
||||
import { transform } from '../utilities/transform.js'
|
||||
import { sanitizeRelationshipIDs } from '../utilities/sanitizeRelationshipIDs.js'
|
||||
|
||||
const migrateModelWithBatching = async ({
|
||||
batchSize,
|
||||
config,
|
||||
db,
|
||||
fields,
|
||||
Model,
|
||||
parentIsLocalized,
|
||||
@@ -19,7 +18,6 @@ const migrateModelWithBatching = async ({
|
||||
}: {
|
||||
batchSize: number
|
||||
config: SanitizedConfig
|
||||
db: MongooseAdapter
|
||||
fields: Field[]
|
||||
Model: Model<any>
|
||||
parentIsLocalized: boolean
|
||||
@@ -51,7 +49,7 @@ const migrateModelWithBatching = async ({
|
||||
}
|
||||
|
||||
for (const doc of docs) {
|
||||
transform({ adapter: db, data: doc, fields, operation: 'write', parentIsLocalized })
|
||||
sanitizeRelationshipIDs({ config, data: doc, fields, parentIsLocalized })
|
||||
}
|
||||
|
||||
await Model.collection.bulkWrite(
|
||||
@@ -126,7 +124,6 @@ export async function migrateRelationshipsV2_V3({
|
||||
await migrateModelWithBatching({
|
||||
batchSize,
|
||||
config,
|
||||
db,
|
||||
fields: collection.fields,
|
||||
Model: db.collections[collection.slug],
|
||||
parentIsLocalized: false,
|
||||
@@ -142,7 +139,6 @@ export async function migrateRelationshipsV2_V3({
|
||||
await migrateModelWithBatching({
|
||||
batchSize,
|
||||
config,
|
||||
db,
|
||||
fields: buildVersionCollectionFields(config, collection),
|
||||
Model: db.versions[collection.slug],
|
||||
parentIsLocalized: false,
|
||||
@@ -171,11 +167,10 @@ export async function migrateRelationshipsV2_V3({
|
||||
|
||||
// in case if the global doesn't exist in the database yet (not saved)
|
||||
if (doc) {
|
||||
transform({
|
||||
adapter: db,
|
||||
sanitizeRelationshipIDs({
|
||||
config,
|
||||
data: doc,
|
||||
fields: global.fields,
|
||||
operation: 'write',
|
||||
})
|
||||
|
||||
await GlobalsModel.collection.updateOne(
|
||||
@@ -196,7 +191,6 @@ export async function migrateRelationshipsV2_V3({
|
||||
await migrateModelWithBatching({
|
||||
batchSize,
|
||||
config,
|
||||
db,
|
||||
fields: buildVersionGlobalFields(config, global),
|
||||
Model: db.versions[global.slug],
|
||||
parentIsLocalized: false,
|
||||
|
||||
@@ -255,25 +255,6 @@ export async function buildSearchParam({
|
||||
return result
|
||||
}
|
||||
|
||||
if (formattedOperator === 'not_like' && typeof formattedValue === 'string') {
|
||||
const words = formattedValue.split(' ')
|
||||
|
||||
const result = {
|
||||
value: {
|
||||
$and: words.map((word) => ({
|
||||
[path]: {
|
||||
$not: {
|
||||
$options: 'i',
|
||||
$regex: word.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&'),
|
||||
},
|
||||
},
|
||||
})),
|
||||
},
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Some operators like 'near' need to define a full query
|
||||
// so if there is no operator key, just return the value
|
||||
if (!operatorKey) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { buildSortParam } from './queries/buildSortParam.js'
|
||||
import { buildJoinAggregation } from './utilities/buildJoinAggregation.js'
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||
|
||||
export const queryDrafts: QueryDrafts = async function queryDrafts(
|
||||
this: MongooseAdapter,
|
||||
@@ -124,18 +124,18 @@ export const queryDrafts: QueryDrafts = async function queryDrafts(
|
||||
result = await VersionModel.paginate(versionQuery, paginationOptions)
|
||||
}
|
||||
|
||||
transform({
|
||||
adapter: this,
|
||||
data: result.docs,
|
||||
fields: buildVersionCollectionFields(this.payload.config, collectionConfig),
|
||||
operation: 'read',
|
||||
})
|
||||
const docs = JSON.parse(JSON.stringify(result.docs))
|
||||
|
||||
for (let i = 0; i < result.docs.length; i++) {
|
||||
const id = result.docs[i].parent
|
||||
result.docs[i] = result.docs[i].version
|
||||
result.docs[i].id = id
|
||||
return {
|
||||
...result,
|
||||
docs: docs.map((doc) => {
|
||||
doc = {
|
||||
_id: doc.parent,
|
||||
id: doc.parent,
|
||||
...doc.version,
|
||||
}
|
||||
|
||||
return sanitizeInternalFields(doc)
|
||||
}),
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ import type { MongooseAdapter } from './index.js'
|
||||
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||
import { sanitizeRelationshipIDs } from './utilities/sanitizeRelationshipIDs.js'
|
||||
|
||||
export const updateGlobal: UpdateGlobal = async function updateGlobal(
|
||||
this: MongooseAdapter,
|
||||
@@ -26,11 +27,25 @@ export const updateGlobal: UpdateGlobal = async function updateGlobal(
|
||||
session: await getSession(this, req),
|
||||
}
|
||||
|
||||
transform({ adapter: this, data, fields, globalSlug: slug, operation: 'write' })
|
||||
let result
|
||||
|
||||
const result: any = await Model.findOneAndUpdate({ globalType: slug }, data, options)
|
||||
const sanitizedData = sanitizeRelationshipIDs({
|
||||
config: this.payload.config,
|
||||
data,
|
||||
fields,
|
||||
})
|
||||
|
||||
transform({ adapter: this, data: result, fields, globalSlug: slug, operation: 'read' })
|
||||
result = await Model.findOneAndUpdate({ globalType: slug }, sanitizedData, options)
|
||||
|
||||
if (!result) {
|
||||
return null
|
||||
}
|
||||
|
||||
result = JSON.parse(JSON.stringify(result))
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id
|
||||
result = sanitizeInternalFields(result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { MongooseAdapter } from './index.js'
|
||||
import { buildQuery } from './queries/buildQuery.js'
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeRelationshipIDs } from './utilities/sanitizeRelationshipIDs.js'
|
||||
|
||||
export async function updateGlobalVersion<T extends TypeWithID>(
|
||||
this: MongooseAdapter,
|
||||
@@ -47,15 +47,26 @@ export async function updateGlobalVersion<T extends TypeWithID>(
|
||||
where: whereToUse,
|
||||
})
|
||||
|
||||
transform({ adapter: this, data: versionData, fields, operation: 'write' })
|
||||
const sanitizedData = sanitizeRelationshipIDs({
|
||||
config: this.payload.config,
|
||||
data: versionData,
|
||||
fields,
|
||||
})
|
||||
|
||||
const doc = await VersionModel.findOneAndUpdate(query, versionData, options)
|
||||
const doc = await VersionModel.findOneAndUpdate(query, sanitizedData, options)
|
||||
|
||||
if (!doc) {
|
||||
return null
|
||||
}
|
||||
|
||||
transform({ adapter: this, data: doc, fields, operation: 'read' })
|
||||
const result = JSON.parse(JSON.stringify(doc))
|
||||
|
||||
return doc
|
||||
const verificationToken = doc._verificationToken
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id
|
||||
if (verificationToken) {
|
||||
result._verificationToken = verificationToken
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import { buildQuery } from './queries/buildQuery.js'
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { handleError } from './utilities/handleError.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeInternalFields } from './utilities/sanitizeInternalFields.js'
|
||||
import { sanitizeRelationshipIDs } from './utilities/sanitizeRelationshipIDs.js'
|
||||
|
||||
export const updateOne: UpdateOne = async function updateOne(
|
||||
this: MongooseAdapter,
|
||||
@@ -38,10 +39,14 @@ export const updateOne: UpdateOne = async function updateOne(
|
||||
|
||||
let result
|
||||
|
||||
transform({ adapter: this, data, fields, operation: 'write' })
|
||||
const sanitizedData = sanitizeRelationshipIDs({
|
||||
config: this.payload.config,
|
||||
data,
|
||||
fields,
|
||||
})
|
||||
|
||||
try {
|
||||
result = await Model.findOneAndUpdate(query, data, options)
|
||||
result = await Model.findOneAndUpdate(query, sanitizedData, options)
|
||||
} catch (error) {
|
||||
handleError({ collection, error, req })
|
||||
}
|
||||
@@ -50,7 +55,9 @@ export const updateOne: UpdateOne = async function updateOne(
|
||||
return null
|
||||
}
|
||||
|
||||
transform({ adapter: this, data: result, fields, operation: 'read' })
|
||||
result = JSON.parse(JSON.stringify(result))
|
||||
result.id = result._id
|
||||
result = sanitizeInternalFields(result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { MongooseAdapter } from './index.js'
|
||||
import { buildQuery } from './queries/buildQuery.js'
|
||||
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
||||
import { getSession } from './utilities/getSession.js'
|
||||
import { transform } from './utilities/transform.js'
|
||||
import { sanitizeRelationshipIDs } from './utilities/sanitizeRelationshipIDs.js'
|
||||
|
||||
export const updateVersion: UpdateVersion = async function updateVersion(
|
||||
this: MongooseAdapter,
|
||||
@@ -45,15 +45,26 @@ export const updateVersion: UpdateVersion = async function updateVersion(
|
||||
where: whereToUse,
|
||||
})
|
||||
|
||||
transform({ adapter: this, data: versionData, fields, operation: 'write' })
|
||||
const sanitizedData = sanitizeRelationshipIDs({
|
||||
config: this.payload.config,
|
||||
data: versionData,
|
||||
fields,
|
||||
})
|
||||
|
||||
const doc = await VersionModel.findOneAndUpdate(query, versionData, options)
|
||||
const doc = await VersionModel.findOneAndUpdate(query, sanitizedData, options)
|
||||
|
||||
if (!doc) {
|
||||
return null
|
||||
}
|
||||
|
||||
transform({ adapter: this, data: doc, fields, operation: 'write' })
|
||||
const result = JSON.parse(JSON.stringify(doc))
|
||||
|
||||
return doc
|
||||
const verificationToken = doc._verificationToken
|
||||
|
||||
// custom id type reset
|
||||
result.id = result._id
|
||||
if (verificationToken) {
|
||||
result._verificationToken = verificationToken
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
20
packages/db-mongodb/src/utilities/sanitizeInternalFields.ts
Normal file
20
packages/db-mongodb/src/utilities/sanitizeInternalFields.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
const internalFields = ['__v']
|
||||
|
||||
export const sanitizeInternalFields = <T extends Record<string, unknown>>(incomingDoc: T): T =>
|
||||
Object.entries(incomingDoc).reduce((newDoc, [key, val]): T => {
|
||||
if (key === '_id') {
|
||||
return {
|
||||
...newDoc,
|
||||
id: val,
|
||||
}
|
||||
}
|
||||
|
||||
if (internalFields.indexOf(key) > -1) {
|
||||
return newDoc
|
||||
}
|
||||
|
||||
return {
|
||||
...newDoc,
|
||||
[key]: val,
|
||||
}
|
||||
}, {} as T)
|
||||
@@ -2,8 +2,7 @@ import { flattenAllFields, type Field, type SanitizedConfig } from 'payload'
|
||||
|
||||
import { Types } from 'mongoose'
|
||||
|
||||
import { transform } from './transform.js'
|
||||
import type { MongooseAdapter } from '../index.js'
|
||||
import { sanitizeRelationshipIDs } from './sanitizeRelationshipIDs.js'
|
||||
|
||||
const flattenRelationshipValues = (obj: Record<string, any>, prefix = ''): Record<string, any> => {
|
||||
return Object.keys(obj).reduce(
|
||||
@@ -298,7 +297,7 @@ const relsData = {
|
||||
},
|
||||
}
|
||||
|
||||
describe('transform', () => {
|
||||
describe('sanitizeRelationshipIDs', () => {
|
||||
it('should sanitize relationships', () => {
|
||||
const data = {
|
||||
...relsData,
|
||||
@@ -383,18 +382,7 @@ describe('transform', () => {
|
||||
}
|
||||
const flattenValuesBefore = Object.values(flattenRelationshipValues(data))
|
||||
|
||||
const mockAdapter = {
|
||||
payload: {
|
||||
config,
|
||||
},
|
||||
} as MongooseAdapter
|
||||
|
||||
transform({
|
||||
adapter: mockAdapter,
|
||||
operation: 'write',
|
||||
data,
|
||||
fields: config.collections[0].fields,
|
||||
})
|
||||
sanitizeRelationshipIDs({ config, data, fields: config.collections[0].fields })
|
||||
const flattenValuesAfter = Object.values(flattenRelationshipValues(data))
|
||||
|
||||
flattenValuesAfter.forEach((value, i) => {
|
||||
165
packages/db-mongodb/src/utilities/sanitizeRelationshipIDs.ts
Normal file
165
packages/db-mongodb/src/utilities/sanitizeRelationshipIDs.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
import type { CollectionConfig, Field, SanitizedConfig, TraverseFieldsCallback } from 'payload'
|
||||
|
||||
import { Types } from 'mongoose'
|
||||
import { traverseFields } from 'payload'
|
||||
import { fieldAffectsData, fieldShouldBeLocalized } from 'payload/shared'
|
||||
|
||||
type Args = {
|
||||
config: SanitizedConfig
|
||||
data: Record<string, unknown>
|
||||
fields: Field[]
|
||||
parentIsLocalized?: boolean
|
||||
}
|
||||
|
||||
interface RelationObject {
|
||||
relationTo: string
|
||||
value: number | string
|
||||
}
|
||||
|
||||
function isValidRelationObject(value: unknown): value is RelationObject {
|
||||
return typeof value === 'object' && value !== null && 'relationTo' in value && 'value' in value
|
||||
}
|
||||
|
||||
const convertValue = ({
|
||||
relatedCollection,
|
||||
value,
|
||||
}: {
|
||||
relatedCollection: CollectionConfig
|
||||
value: number | string
|
||||
}): number | string | Types.ObjectId => {
|
||||
const customIDField = relatedCollection.fields.find(
|
||||
(field) => fieldAffectsData(field) && field.name === 'id',
|
||||
)
|
||||
|
||||
if (customIDField) {
|
||||
return value
|
||||
}
|
||||
|
||||
try {
|
||||
return new Types.ObjectId(value)
|
||||
} catch {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
const sanitizeRelationship = ({ config, field, locale, ref, value }) => {
|
||||
let relatedCollection: CollectionConfig | undefined
|
||||
let result = value
|
||||
|
||||
const hasManyRelations = typeof field.relationTo !== 'string'
|
||||
|
||||
if (!hasManyRelations) {
|
||||
relatedCollection = config.collections?.find(({ slug }) => slug === field.relationTo)
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
result = value.map((val) => {
|
||||
// Handle has many
|
||||
if (relatedCollection && val && (typeof val === 'string' || typeof val === 'number')) {
|
||||
return convertValue({
|
||||
relatedCollection,
|
||||
value: val,
|
||||
})
|
||||
}
|
||||
|
||||
// Handle has many - polymorphic
|
||||
if (isValidRelationObject(val)) {
|
||||
const relatedCollectionForSingleValue = config.collections?.find(
|
||||
({ slug }) => slug === val.relationTo,
|
||||
)
|
||||
|
||||
if (relatedCollectionForSingleValue) {
|
||||
return {
|
||||
relationTo: val.relationTo,
|
||||
value: convertValue({
|
||||
relatedCollection: relatedCollectionForSingleValue,
|
||||
value: val.value,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val
|
||||
})
|
||||
}
|
||||
|
||||
// Handle has one - polymorphic
|
||||
if (isValidRelationObject(value)) {
|
||||
relatedCollection = config.collections?.find(({ slug }) => slug === value.relationTo)
|
||||
|
||||
if (relatedCollection) {
|
||||
result = {
|
||||
relationTo: value.relationTo,
|
||||
value: convertValue({ relatedCollection, value: value.value }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle has one
|
||||
if (relatedCollection && value && (typeof value === 'string' || typeof value === 'number')) {
|
||||
result = convertValue({
|
||||
relatedCollection,
|
||||
value,
|
||||
})
|
||||
}
|
||||
if (locale) {
|
||||
ref[locale] = result
|
||||
} else {
|
||||
ref[field.name] = result
|
||||
}
|
||||
}
|
||||
|
||||
export const sanitizeRelationshipIDs = ({
|
||||
config,
|
||||
data,
|
||||
fields,
|
||||
parentIsLocalized,
|
||||
}: Args): Record<string, unknown> => {
|
||||
const sanitize: TraverseFieldsCallback = ({ field, ref }) => {
|
||||
if (!ref || typeof ref !== 'object') {
|
||||
return
|
||||
}
|
||||
|
||||
if (field.type === 'relationship' || field.type === 'upload') {
|
||||
if (!ref[field.name]) {
|
||||
return
|
||||
}
|
||||
|
||||
// handle localized relationships
|
||||
if (config.localization && fieldShouldBeLocalized({ field, parentIsLocalized })) {
|
||||
const locales = config.localization.locales
|
||||
const fieldRef = ref[field.name]
|
||||
if (typeof fieldRef !== 'object') {
|
||||
return
|
||||
}
|
||||
|
||||
for (const { code } of locales) {
|
||||
const value = ref[field.name][code]
|
||||
if (value) {
|
||||
sanitizeRelationship({ config, field, locale: code, ref: fieldRef, value })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// handle non-localized relationships
|
||||
sanitizeRelationship({
|
||||
config,
|
||||
field,
|
||||
locale: undefined,
|
||||
ref,
|
||||
value: ref[field.name],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverseFields({
|
||||
callback: sanitize,
|
||||
config,
|
||||
fields,
|
||||
fillEmpty: false,
|
||||
parentIsLocalized,
|
||||
ref: data,
|
||||
})
|
||||
|
||||
return data
|
||||
}
|
||||
@@ -1,347 +0,0 @@
|
||||
import type {
|
||||
CollectionConfig,
|
||||
DateField,
|
||||
Field,
|
||||
JoinField,
|
||||
RelationshipField,
|
||||
SanitizedConfig,
|
||||
TraverseFieldsCallback,
|
||||
UploadField,
|
||||
} from 'payload'
|
||||
|
||||
import { Types } from 'mongoose'
|
||||
import { traverseFields } from 'payload'
|
||||
import { fieldAffectsData, fieldShouldBeLocalized } from 'payload/shared'
|
||||
|
||||
import type { MongooseAdapter } from '../index.js'
|
||||
|
||||
interface RelationObject {
|
||||
relationTo: string
|
||||
value: number | string
|
||||
}
|
||||
|
||||
function isValidRelationObject(value: unknown): value is RelationObject {
|
||||
return typeof value === 'object' && value !== null && 'relationTo' in value && 'value' in value
|
||||
}
|
||||
|
||||
const convertRelationshipValue = ({
|
||||
operation,
|
||||
relatedCollection,
|
||||
validateRelationships,
|
||||
value,
|
||||
}: {
|
||||
operation: Args['operation']
|
||||
relatedCollection: CollectionConfig
|
||||
validateRelationships?: boolean
|
||||
value: unknown
|
||||
}) => {
|
||||
const customIDField = relatedCollection.fields.find(
|
||||
(field) => fieldAffectsData(field) && field.name === 'id',
|
||||
)
|
||||
|
||||
if (operation === 'read') {
|
||||
if (value instanceof Types.ObjectId) {
|
||||
return value.toHexString()
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
if (customIDField) {
|
||||
return value
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
return new Types.ObjectId(value)
|
||||
} catch (e) {
|
||||
if (validateRelationships) {
|
||||
throw e
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
const sanitizeRelationship = ({
|
||||
config,
|
||||
field,
|
||||
locale,
|
||||
operation,
|
||||
ref,
|
||||
validateRelationships,
|
||||
value,
|
||||
}: {
|
||||
config: SanitizedConfig
|
||||
field: JoinField | RelationshipField | UploadField
|
||||
locale?: string
|
||||
operation: Args['operation']
|
||||
ref: Record<string, unknown>
|
||||
validateRelationships?: boolean
|
||||
value?: unknown
|
||||
}) => {
|
||||
if (field.type === 'join') {
|
||||
if (
|
||||
operation === 'read' &&
|
||||
value &&
|
||||
typeof value === 'object' &&
|
||||
'docs' in value &&
|
||||
Array.isArray(value.docs)
|
||||
) {
|
||||
for (let i = 0; i < value.docs.length; i++) {
|
||||
const item = value.docs[i]
|
||||
|
||||
if (item instanceof Types.ObjectId) {
|
||||
value.docs[i] = item.toHexString()
|
||||
} else if (Array.isArray(field.collection) && item) {
|
||||
// Fields here for polymorphic joins cannot be determinted, JSON.parse needed
|
||||
value.docs[i] = JSON.parse(JSON.stringify(value.docs[i]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
let relatedCollection: CollectionConfig | undefined
|
||||
let result = value
|
||||
|
||||
const hasManyRelations = typeof field.relationTo !== 'string'
|
||||
|
||||
if (!hasManyRelations) {
|
||||
relatedCollection = config.collections?.find(({ slug }) => slug === field.relationTo)
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
result = value.map((val) => {
|
||||
// Handle has many - polymorphic
|
||||
if (isValidRelationObject(val)) {
|
||||
const relatedCollectionForSingleValue = config.collections?.find(
|
||||
({ slug }) => slug === val.relationTo,
|
||||
)
|
||||
|
||||
if (relatedCollectionForSingleValue) {
|
||||
return {
|
||||
relationTo: val.relationTo,
|
||||
value: convertRelationshipValue({
|
||||
operation,
|
||||
relatedCollection: relatedCollectionForSingleValue,
|
||||
validateRelationships,
|
||||
value: val.value,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (relatedCollection) {
|
||||
return convertRelationshipValue({
|
||||
operation,
|
||||
relatedCollection,
|
||||
validateRelationships,
|
||||
value: val,
|
||||
})
|
||||
}
|
||||
|
||||
return val
|
||||
})
|
||||
}
|
||||
// Handle has one - polymorphic
|
||||
else if (isValidRelationObject(value)) {
|
||||
relatedCollection = config.collections?.find(({ slug }) => slug === value.relationTo)
|
||||
|
||||
if (relatedCollection) {
|
||||
result = {
|
||||
relationTo: value.relationTo,
|
||||
value: convertRelationshipValue({
|
||||
operation,
|
||||
relatedCollection,
|
||||
validateRelationships,
|
||||
value: value.value,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
// Handle has one
|
||||
else if (relatedCollection) {
|
||||
result = convertRelationshipValue({
|
||||
operation,
|
||||
relatedCollection,
|
||||
validateRelationships,
|
||||
value,
|
||||
})
|
||||
}
|
||||
|
||||
if (locale) {
|
||||
ref[locale] = result
|
||||
} else {
|
||||
ref[field.name] = result
|
||||
}
|
||||
}
|
||||
|
||||
const sanitizeDate = ({
|
||||
field,
|
||||
locale,
|
||||
ref,
|
||||
value,
|
||||
}: {
|
||||
field: DateField
|
||||
locale?: string
|
||||
ref: Record<string, unknown>
|
||||
value: unknown
|
||||
}) => {
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (value instanceof Date) {
|
||||
value = value.toISOString()
|
||||
}
|
||||
|
||||
if (locale) {
|
||||
ref[locale] = value
|
||||
} else {
|
||||
ref[field.name] = value
|
||||
}
|
||||
}
|
||||
|
||||
type Args = {
|
||||
/** instance of the adapter */
|
||||
adapter: MongooseAdapter
|
||||
/** data to transform, can be an array of documents or a single document */
|
||||
data: Record<string, unknown> | Record<string, unknown>[]
|
||||
/** fields accossiated with the data */
|
||||
fields: Field[]
|
||||
/** slug of the global, pass only when the operation is `write` */
|
||||
globalSlug?: string
|
||||
/**
|
||||
* Type of the operation
|
||||
* read - sanitizes ObjectIDs, Date to strings.
|
||||
* write - sanitizes string relationships to ObjectIDs.
|
||||
*/
|
||||
operation: 'read' | 'write'
|
||||
parentIsLocalized?: boolean
|
||||
/**
|
||||
* Throw errors on invalid relationships
|
||||
* @default true
|
||||
*/
|
||||
validateRelationships?: boolean
|
||||
}
|
||||
|
||||
export const transform = ({
|
||||
adapter,
|
||||
data,
|
||||
fields,
|
||||
globalSlug,
|
||||
operation,
|
||||
parentIsLocalized,
|
||||
validateRelationships = true,
|
||||
}: Args) => {
|
||||
if (Array.isArray(data)) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
transform({ adapter, data: data[i], fields, globalSlug, operation, validateRelationships })
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const {
|
||||
payload: { config },
|
||||
} = adapter
|
||||
|
||||
if (operation === 'read') {
|
||||
delete data['__v']
|
||||
data.id = data._id
|
||||
delete data['_id']
|
||||
|
||||
if (data.id instanceof Types.ObjectId) {
|
||||
data.id = data.id.toHexString()
|
||||
}
|
||||
}
|
||||
|
||||
if (operation === 'write' && globalSlug) {
|
||||
data.globalType = globalSlug
|
||||
}
|
||||
|
||||
const sanitize: TraverseFieldsCallback = ({ field, ref }) => {
|
||||
if (!ref || typeof ref !== 'object') {
|
||||
return
|
||||
}
|
||||
|
||||
if (field.type === 'date' && operation === 'read' && ref[field.name]) {
|
||||
if (config.localization && fieldShouldBeLocalized({ field, parentIsLocalized })) {
|
||||
const fieldRef = ref[field.name]
|
||||
if (!fieldRef || typeof fieldRef !== 'object') {
|
||||
return
|
||||
}
|
||||
|
||||
for (const locale of config.localization.localeCodes) {
|
||||
sanitizeDate({
|
||||
field,
|
||||
ref: fieldRef,
|
||||
value: fieldRef[locale],
|
||||
})
|
||||
}
|
||||
} else {
|
||||
sanitizeDate({
|
||||
field,
|
||||
ref: ref as Record<string, unknown>,
|
||||
value: ref[field.name],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
field.type === 'relationship' ||
|
||||
field.type === 'upload' ||
|
||||
(operation === 'read' && field.type === 'join')
|
||||
) {
|
||||
if (!ref[field.name]) {
|
||||
return
|
||||
}
|
||||
|
||||
// handle localized relationships
|
||||
if (config.localization && fieldShouldBeLocalized({ field, parentIsLocalized })) {
|
||||
const locales = config.localization.locales
|
||||
const fieldRef = ref[field.name]
|
||||
if (typeof fieldRef !== 'object') {
|
||||
return
|
||||
}
|
||||
|
||||
for (const { code } of locales) {
|
||||
const value = ref[field.name][code]
|
||||
if (value) {
|
||||
sanitizeRelationship({
|
||||
config,
|
||||
field,
|
||||
locale: code,
|
||||
operation,
|
||||
ref: fieldRef,
|
||||
validateRelationships,
|
||||
value,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// handle non-localized relationships
|
||||
sanitizeRelationship({
|
||||
config,
|
||||
field,
|
||||
locale: undefined,
|
||||
operation,
|
||||
ref: ref as Record<string, unknown>,
|
||||
validateRelationships,
|
||||
value: ref[field.name],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverseFields({
|
||||
callback: sanitize,
|
||||
config,
|
||||
fields,
|
||||
fillEmpty: false,
|
||||
parentIsLocalized,
|
||||
ref: data,
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-sqlite",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "The officially supported SQLite database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -50,12 +50,10 @@ const createConstraint = ({
|
||||
const newAlias = `${pathSegments[0]}_alias_${pathSegments.length - 1}`
|
||||
let formattedValue = value
|
||||
let formattedOperator = operator
|
||||
|
||||
if (['contains', 'like'].includes(operator)) {
|
||||
formattedOperator = 'like'
|
||||
formattedValue = `%${value}%`
|
||||
} else if (['not_like', 'notlike'].includes(operator)) {
|
||||
formattedOperator = 'not like'
|
||||
formattedValue = `%${value}%`
|
||||
} else if (operator === 'equals') {
|
||||
formattedOperator = '='
|
||||
}
|
||||
@@ -63,7 +61,7 @@ const createConstraint = ({
|
||||
return `EXISTS (
|
||||
SELECT 1
|
||||
FROM json_each(${alias}.value -> '${pathSegments[0]}') AS ${newAlias}
|
||||
WHERE COALESCE(${newAlias}.value ->> '${pathSegments[1]}', '') ${formattedOperator} '${formattedValue}'
|
||||
WHERE ${newAlias}.value ->> '${pathSegments[1]}' ${formattedOperator} '${formattedValue}'
|
||||
)`
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import {
|
||||
updateOne,
|
||||
updateVersion,
|
||||
} from '@payloadcms/drizzle'
|
||||
import { like, notLike } from 'drizzle-orm'
|
||||
import { like } from 'drizzle-orm'
|
||||
import { createDatabaseAdapter, defaultBeginTransaction } from 'payload'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
@@ -81,7 +81,6 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
|
||||
...operatorMap,
|
||||
contains: like,
|
||||
like,
|
||||
not_like: notLike,
|
||||
} as unknown as Operators
|
||||
|
||||
return createDatabaseAdapter<SQLiteAdapter>({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-vercel-postgres",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "Vercel Postgres adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/drizzle",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "A library of shared functions used by different payload database adapters",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -7,13 +7,12 @@ const operatorMap: Record<string, string> = {
|
||||
like: 'like_regex',
|
||||
not_equals: '!=',
|
||||
not_in: 'in',
|
||||
not_like: '!like_regex',
|
||||
}
|
||||
|
||||
const sanitizeValue = (value: unknown, operator?: string) => {
|
||||
if (typeof value === 'string') {
|
||||
// ignore casing with like or not_like
|
||||
return `"${['like', 'not_like'].includes(operator) ? '(?i)' : ''}${value}"`
|
||||
// ignore casing with like
|
||||
return `"${operator === 'like' ? '(?i)' : ''}${value}"`
|
||||
}
|
||||
|
||||
return value as string
|
||||
@@ -36,10 +35,6 @@ export const createJSONQuery = ({ column, operator, pathSegments, value }: Creat
|
||||
})
|
||||
} else if (operator === 'exists') {
|
||||
sql = `${value === false ? 'NOT ' : ''}jsonb_path_exists(${columnName}, '$.${jsonPaths}')`
|
||||
} else if (['not_like'].includes(operator)) {
|
||||
const mappedOperator = operatorMap[operator]
|
||||
|
||||
sql = `NOT jsonb_path_exists(${columnName}, '$.${jsonPaths} ? (@ ${mappedOperator.substring(1)} ${sanitizeValue(value, operator)})')`
|
||||
} else {
|
||||
sql = `jsonb_path_exists(${columnName}, '$.${jsonPaths} ? (@ ${operatorMap[operator]} ${sanitizeValue(value, operator)})')`
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
lt,
|
||||
lte,
|
||||
ne,
|
||||
notIlike,
|
||||
notInArray,
|
||||
or,
|
||||
type SQL,
|
||||
@@ -32,7 +31,6 @@ type OperatorKeys =
|
||||
| 'like'
|
||||
| 'not_equals'
|
||||
| 'not_in'
|
||||
| 'not_like'
|
||||
| 'or'
|
||||
|
||||
export type Operators = Record<OperatorKeys, (column: Column, value: SQLWrapper | unknown) => SQL>
|
||||
@@ -50,7 +48,6 @@ export const operatorMap: Operators = {
|
||||
less_than_equal: lte,
|
||||
like: ilike,
|
||||
not_equals: ne,
|
||||
not_like: notIlike,
|
||||
// TODO: support this
|
||||
// all: all,
|
||||
not_in: notInArray,
|
||||
|
||||
@@ -161,7 +161,6 @@ export function parseParams({
|
||||
like: { operator: 'like', wildcard: '%' },
|
||||
not_equals: { operator: '<>', wildcard: '' },
|
||||
not_in: { operator: 'not in', wildcard: '' },
|
||||
not_like: { operator: 'not like', wildcard: '%' },
|
||||
}
|
||||
|
||||
let formattedValue = val
|
||||
@@ -176,15 +175,11 @@ export function parseParams({
|
||||
formattedValue = ''
|
||||
}
|
||||
|
||||
let jsonQuerySelector = `${table[columnName].name}${jsonQuery}`
|
||||
|
||||
if (adapter.name === 'sqlite' && operator === 'not_like') {
|
||||
jsonQuerySelector = `COALESCE(${table[columnName].name}${jsonQuery}, '')`
|
||||
}
|
||||
|
||||
const rawSQLQuery = `${jsonQuerySelector} ${operatorKeys[operator].operator} ${formattedValue}`
|
||||
|
||||
constraints.push(sql.raw(rawSQLQuery))
|
||||
constraints.push(
|
||||
sql.raw(
|
||||
`${table[columnName].name}${jsonQuery} ${operatorKeys[operator].operator} ${formattedValue}`,
|
||||
),
|
||||
)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-nodemailer",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "Payload Nodemailer Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-resend",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "Payload Resend Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/graphql",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-react",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "The official React SDK for Payload Live Preview",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-vue",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "The official Vue SDK for Payload Live Preview",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "The official live preview JavaScript SDK for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/next",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -96,6 +96,7 @@
|
||||
"qs-esm": "7.0.2",
|
||||
"react-diff-viewer-continued": "4.0.4",
|
||||
"sass": "1.77.4",
|
||||
"sonner": "^1.7.0",
|
||||
"uuid": "10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
import type { DefaultDocumentIDType, NavPreferences, Payload, User } from 'payload'
|
||||
import type { NavPreferences, Payload, User } from 'payload'
|
||||
|
||||
import { cache } from 'react'
|
||||
|
||||
export const getNavPrefs = cache(
|
||||
async (
|
||||
payload: Payload,
|
||||
userID: DefaultDocumentIDType,
|
||||
userSlug: string,
|
||||
): Promise<NavPreferences> => {
|
||||
return userSlug
|
||||
async ({ payload, user }: { payload: Payload; user: User }): Promise<NavPreferences> =>
|
||||
user
|
||||
? await payload
|
||||
.find({
|
||||
collection: 'payload-preferences',
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
user,
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
@@ -24,18 +20,17 @@ export const getNavPrefs = cache(
|
||||
},
|
||||
{
|
||||
'user.relationTo': {
|
||||
equals: userSlug,
|
||||
equals: user.collection,
|
||||
},
|
||||
},
|
||||
{
|
||||
'user.value': {
|
||||
equals: userID,
|
||||
equals: user.id,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
?.then((res) => res?.docs?.[0]?.value)
|
||||
: null
|
||||
},
|
||||
: null,
|
||||
)
|
||||
|
||||
@@ -68,7 +68,7 @@ export const DefaultNav: React.FC<NavProps> = async (props) => {
|
||||
i18n,
|
||||
)
|
||||
|
||||
const navPreferences = await getNavPrefs(payload, user?.id, user?.collection)
|
||||
const navPreferences = await getNavPrefs({ payload, user })
|
||||
|
||||
const LogoutComponent = RenderServerComponent({
|
||||
clientProps: {
|
||||
|
||||
@@ -4,10 +4,12 @@ import type { ImportMap, LanguageOptions, SanitizedConfig, ServerFunctionClient
|
||||
import { rtlLanguages } from '@payloadcms/translations'
|
||||
import { ProgressBar, RootProvider } from '@payloadcms/ui'
|
||||
import { getClientConfig } from '@payloadcms/ui/utilities/getClientConfig'
|
||||
import { cookies as nextCookies } from 'next/headers.js'
|
||||
import { headers as getHeaders, cookies as nextCookies } from 'next/headers.js'
|
||||
import { getPayload, getRequestLanguage, parseCookies } from 'payload'
|
||||
import React from 'react'
|
||||
|
||||
import { getNavPrefs } from '../../elements/Nav/getNavPrefs.js'
|
||||
import { getRequestLocale } from '../../utilities/getRequestLocale.js'
|
||||
import { getRequestTheme } from '../../utilities/getRequestTheme.js'
|
||||
import { initReq } from '../../utilities/initReq.js'
|
||||
import { checkDependencies } from './checkDependencies.js'
|
||||
@@ -33,16 +35,16 @@ export const RootLayout = async ({
|
||||
}) => {
|
||||
checkDependencies()
|
||||
|
||||
const {
|
||||
const config = await configPromise
|
||||
|
||||
const headers = await getHeaders()
|
||||
const cookies = parseCookies(headers)
|
||||
|
||||
const languageCode = getRequestLanguage({
|
||||
config,
|
||||
cookies,
|
||||
headers,
|
||||
languageCode,
|
||||
permissions,
|
||||
req,
|
||||
req: {
|
||||
payload: { config },
|
||||
},
|
||||
} = await initReq({ configPromise, importMap })
|
||||
})
|
||||
|
||||
const theme = getRequestTheme({
|
||||
config,
|
||||
@@ -50,6 +52,10 @@ export const RootLayout = async ({
|
||||
headers,
|
||||
})
|
||||
|
||||
const payload = await getPayload({ config, importMap })
|
||||
|
||||
const { permissions, req } = await initReq(config)
|
||||
|
||||
const dir = (rtlLanguages as unknown as AcceptedLanguages[]).includes(languageCode)
|
||||
? 'RTL'
|
||||
: 'LTR'
|
||||
@@ -77,7 +83,7 @@ export const RootLayout = async ({
|
||||
})
|
||||
}
|
||||
|
||||
const navPrefs = await getNavPrefs(req.payload, req.user?.id, req.user?.collection)
|
||||
const navPrefs = await getNavPrefs({ payload, user: req.user })
|
||||
|
||||
const clientConfig = getClientConfig({
|
||||
config,
|
||||
@@ -99,6 +105,10 @@ export const RootLayout = async ({
|
||||
clientConfig.localization.localeCodes = config.localization.locales.map(({ code }) => code)
|
||||
}
|
||||
|
||||
const locale = await getRequestLocale({
|
||||
req,
|
||||
})
|
||||
|
||||
return (
|
||||
<html
|
||||
data-theme={theme}
|
||||
@@ -117,7 +127,7 @@ export const RootLayout = async ({
|
||||
isNavOpen={navPrefs?.open ?? true}
|
||||
languageCode={languageCode}
|
||||
languageOptions={languageOptions}
|
||||
locale={req.locale}
|
||||
locale={locale?.code}
|
||||
permissions={permissions}
|
||||
serverFunction={serverFunction}
|
||||
switchLanguageServerAction={switchLanguageServerAction}
|
||||
@@ -129,11 +139,11 @@ export const RootLayout = async ({
|
||||
{Array.isArray(config.admin?.components?.providers) &&
|
||||
config.admin?.components?.providers.length > 0 ? (
|
||||
<NestProviders
|
||||
importMap={req.payload.importMap}
|
||||
importMap={payload.importMap}
|
||||
providers={config.admin?.components?.providers}
|
||||
serverProps={{
|
||||
i18n: req.i18n,
|
||||
payload: req.payload,
|
||||
payload,
|
||||
permissions,
|
||||
user: req.user,
|
||||
}}
|
||||
|
||||
@@ -1,41 +1,40 @@
|
||||
import type { DefaultDocumentIDType, Payload } from 'payload'
|
||||
import type { Payload, User } from 'payload'
|
||||
|
||||
import { cache } from 'react'
|
||||
|
||||
export const getPreferences = cache(
|
||||
async <T>(
|
||||
key: string,
|
||||
payload: Payload,
|
||||
userID: DefaultDocumentIDType,
|
||||
userSlug: string,
|
||||
): Promise<{ id: DefaultDocumentIDType; value: T }> => {
|
||||
const result = (await payload
|
||||
.find({
|
||||
collection: 'payload-preferences',
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
key: {
|
||||
equals: key,
|
||||
async <T>(key: string, payload: Payload, user: User): Promise<T> => {
|
||||
let result: T = null
|
||||
|
||||
try {
|
||||
result = await payload
|
||||
.find({
|
||||
collection: 'payload-preferences',
|
||||
depth: 0,
|
||||
limit: 1,
|
||||
user,
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
'user.relationTo': {
|
||||
equals: payload.config.admin.user,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'user.relationTo': {
|
||||
equals: userSlug,
|
||||
{
|
||||
'user.value': {
|
||||
equals: user.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'user.value': {
|
||||
equals: userID,
|
||||
{
|
||||
key: {
|
||||
equals: key,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
.then((res) => res.docs?.[0])) as { id: DefaultDocumentIDType; value: T }
|
||||
],
|
||||
},
|
||||
})
|
||||
?.then((res) => res.docs?.[0]?.value as T)
|
||||
} catch (_err) {} // eslint-disable-line no-empty
|
||||
|
||||
return result
|
||||
},
|
||||
|
||||
@@ -18,19 +18,10 @@ export async function getRequestLocale({ req }: GetRequestLocalesArgs): Promise<
|
||||
}
|
||||
|
||||
return (
|
||||
(req.user &&
|
||||
findLocaleFromCode(
|
||||
req.payload.config.localization,
|
||||
localeFromParams ||
|
||||
(
|
||||
await getPreferences<Locale['code']>(
|
||||
'locale',
|
||||
req.payload,
|
||||
req.user.id,
|
||||
req.user.collection,
|
||||
)
|
||||
)?.value,
|
||||
)) ||
|
||||
findLocaleFromCode(
|
||||
req.payload.config.localization,
|
||||
localeFromParams || (await getPreferences<Locale['code']>('locale', req.payload, req.user)),
|
||||
) ||
|
||||
findLocaleFromCode(
|
||||
req.payload.config.localization,
|
||||
req.payload.config.localization.defaultLocale || 'en',
|
||||
|
||||
@@ -13,10 +13,7 @@ import { initReq } from './initReq.js'
|
||||
export const handleServerFunctions: ServerFunctionHandler = async (args) => {
|
||||
const { name: fnKey, args: fnArgs, config: configPromise, importMap } = args
|
||||
|
||||
const { req } = await initReq({
|
||||
configPromise,
|
||||
importMap,
|
||||
})
|
||||
const { req } = await initReq(configPromise)
|
||||
|
||||
const augmentedArgs: Parameters<ServerFunction>[0] = {
|
||||
...fnArgs,
|
||||
|
||||
@@ -18,32 +18,31 @@ export const initPage = async ({
|
||||
importMap,
|
||||
route,
|
||||
searchParams,
|
||||
useLayoutReq,
|
||||
}: Args): Promise<InitPageResult> => {
|
||||
const headers = await getHeaders()
|
||||
const payload = await getPayload({ config: configPromise, importMap })
|
||||
const queryString = `${qs.stringify(searchParams ?? {}, { addQueryPrefix: true })}`
|
||||
|
||||
const {
|
||||
cookies,
|
||||
locale,
|
||||
permissions,
|
||||
req,
|
||||
req: { payload },
|
||||
} = await initReq({
|
||||
configPromise,
|
||||
importMap,
|
||||
overrides: {
|
||||
fallbackLocale: false,
|
||||
queryString,
|
||||
},
|
||||
urlSuffix: `${route}${searchParams ? queryString : ''}`,
|
||||
})
|
||||
|
||||
const {
|
||||
collections,
|
||||
globals,
|
||||
routes: { admin: adminRoute },
|
||||
} = payload.config
|
||||
|
||||
const cookies = parseCookies(headers)
|
||||
|
||||
const { locale, permissions, req } = await initReq(payload.config, {
|
||||
fallbackLocale: false,
|
||||
req: {
|
||||
headers,
|
||||
query: qs.parse(queryString, {
|
||||
depth: 10,
|
||||
ignoreQueryPrefix: true,
|
||||
}),
|
||||
url: `${payload.config.serverURL}${route}${searchParams ? queryString : ''}`,
|
||||
},
|
||||
})
|
||||
|
||||
const languageOptions = Object.entries(payload.config.i18n.supportedLanguages || {}).reduce(
|
||||
(acc, [language, languageConfig]) => {
|
||||
if (Object.keys(payload.config.i18n.supportedLanguages).includes(language)) {
|
||||
|
||||
@@ -20,15 +20,4 @@ export type Args = {
|
||||
* The search parameters of the current route provided to all pages in Next.js.
|
||||
*/
|
||||
searchParams: { [key: string]: string | string[] | undefined }
|
||||
/**
|
||||
* If `useLayoutReq` is `true`, this page will use the cached `req` created by the root layout
|
||||
* instead of creating a new one.
|
||||
*
|
||||
* This improves performance for pages that are able to share the same `req` as the root layout,
|
||||
* as permissions do not need to be re-calculated.
|
||||
*
|
||||
* If the page has unique query and url params that need to be part of the `req` object, or if you
|
||||
* need permissions calculation to respect those you should not use this property.
|
||||
*/
|
||||
useLayoutReq?: boolean
|
||||
}
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
import type { AcceptedLanguages, I18n, I18nClient } from '@payloadcms/translations'
|
||||
import type {
|
||||
ImportMap,
|
||||
Locale,
|
||||
Payload,
|
||||
PayloadRequest,
|
||||
SanitizedConfig,
|
||||
SanitizedPermissions,
|
||||
User,
|
||||
} from 'payload'
|
||||
import type { I18n, I18nClient } from '@payloadcms/translations'
|
||||
import type { Locale, PayloadRequest, SanitizedConfig, SanitizedPermissions } from 'payload'
|
||||
|
||||
import { initI18n } from '@payloadcms/translations'
|
||||
import { headers as getHeaders } from 'next/headers.js'
|
||||
@@ -19,137 +11,78 @@ import {
|
||||
getRequestLanguage,
|
||||
parseCookies,
|
||||
} from 'payload'
|
||||
import * as qs from 'qs-esm'
|
||||
import { cache } from 'react'
|
||||
|
||||
import { getRequestLocale } from './getRequestLocale.js'
|
||||
|
||||
type Result = {
|
||||
cookies: Map<string, string>
|
||||
headers: Awaited<ReturnType<typeof getHeaders>>
|
||||
languageCode: AcceptedLanguages
|
||||
locale?: Locale
|
||||
permissions: SanitizedPermissions
|
||||
req: PayloadRequest
|
||||
}
|
||||
const cachedInitI18n = cache(async (config: SanitizedConfig, languageCode: AcceptedLanguages) => {
|
||||
return await initI18n({
|
||||
config: config.i18n,
|
||||
context: 'client',
|
||||
language: languageCode,
|
||||
})
|
||||
})
|
||||
|
||||
const cachedExecuteAuthStrategies = cache(
|
||||
async (headers: Awaited<ReturnType<typeof getHeaders>>, payload: Payload) => {
|
||||
return await executeAuthStrategies({
|
||||
headers,
|
||||
payload,
|
||||
})
|
||||
},
|
||||
)
|
||||
export const initReq = cache(async function (
|
||||
configPromise: Promise<SanitizedConfig> | SanitizedConfig,
|
||||
overrides?: Parameters<typeof createLocalReq>[0],
|
||||
): Promise<Result> {
|
||||
const config = await configPromise
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
const cachedCreateLocalReq = cache(
|
||||
async (
|
||||
fallbackLocale: false | string,
|
||||
headers: Awaited<ReturnType<typeof getHeaders>>,
|
||||
i18n: I18n,
|
||||
queryString: string | undefined,
|
||||
responseHeaders: Headers,
|
||||
url: string,
|
||||
user: null | User,
|
||||
payload: Payload,
|
||||
) => {
|
||||
return await createLocalReq(
|
||||
{
|
||||
fallbackLocale,
|
||||
req: {
|
||||
headers,
|
||||
host: headers.get('host'),
|
||||
i18n,
|
||||
query: queryString
|
||||
? qs.parse(queryString, {
|
||||
depth: 10,
|
||||
ignoreQueryPrefix: true,
|
||||
})
|
||||
: undefined,
|
||||
responseHeaders,
|
||||
url,
|
||||
user,
|
||||
},
|
||||
},
|
||||
payload,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
const cachedGetRequestLocale = cache(async (req: PayloadRequest) => {
|
||||
return await getRequestLocale({
|
||||
req,
|
||||
})
|
||||
})
|
||||
|
||||
const cachedGetAccessResults = cache(async (req: PayloadRequest) => {
|
||||
return await getAccessResults({
|
||||
req,
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* Initializes a full request object, including the `req` object and access control.
|
||||
* As access control and getting the request locale is dependent on the current URL and
|
||||
*/
|
||||
export const initReq = async function ({
|
||||
configPromise,
|
||||
importMap,
|
||||
overrides,
|
||||
urlSuffix,
|
||||
}: {
|
||||
configPromise: Promise<SanitizedConfig> | SanitizedConfig
|
||||
importMap: ImportMap
|
||||
overrides?: {
|
||||
fallbackLocale?: false | string
|
||||
queryString?: string
|
||||
}
|
||||
urlSuffix?: string
|
||||
}): Promise<Result> {
|
||||
const headers = await getHeaders()
|
||||
const cookies = parseCookies(headers)
|
||||
|
||||
const config = await configPromise
|
||||
const payload = await getPayload({ config, importMap })
|
||||
const languageCode = getRequestLanguage({
|
||||
config,
|
||||
cookies,
|
||||
headers,
|
||||
})
|
||||
|
||||
const i18n: I18nClient = await cachedInitI18n(config, languageCode)
|
||||
const i18n: I18nClient = await initI18n({
|
||||
config: config.i18n,
|
||||
context: 'client',
|
||||
language: languageCode,
|
||||
})
|
||||
|
||||
const { responseHeaders, user } = await cachedExecuteAuthStrategies(headers, payload)
|
||||
|
||||
const req = await cachedCreateLocalReq(
|
||||
overrides?.fallbackLocale,
|
||||
/**
|
||||
* Cannot simply call `payload.auth` here, as we need the user to get the locale, and we need the locale to get the access results
|
||||
* I.e. the `payload.auth` function would call `getAccessResults` without a fully-formed `req` object
|
||||
*/
|
||||
const { responseHeaders, user } = await executeAuthStrategies({
|
||||
headers,
|
||||
i18n as I18n,
|
||||
overrides?.queryString,
|
||||
responseHeaders,
|
||||
`${payload.config.serverURL}${urlSuffix || ''}`,
|
||||
user,
|
||||
payload,
|
||||
})
|
||||
|
||||
const { req: reqOverrides, ...optionsOverrides } = overrides || {}
|
||||
|
||||
const req = await createLocalReq(
|
||||
{
|
||||
req: {
|
||||
headers,
|
||||
host: headers.get('host'),
|
||||
i18n: i18n as I18n,
|
||||
responseHeaders,
|
||||
url: `${payload.config.serverURL}`,
|
||||
user,
|
||||
...(reqOverrides || {}),
|
||||
},
|
||||
...(optionsOverrides || {}),
|
||||
},
|
||||
payload,
|
||||
)
|
||||
|
||||
const locale = await cachedGetRequestLocale(req)
|
||||
const locale = await getRequestLocale({
|
||||
req,
|
||||
})
|
||||
|
||||
req.locale = locale?.code
|
||||
|
||||
const permissions = await cachedGetAccessResults(req)
|
||||
const permissions = await getAccessResults({
|
||||
req,
|
||||
})
|
||||
|
||||
return {
|
||||
cookies,
|
||||
headers,
|
||||
languageCode,
|
||||
locale,
|
||||
permissions,
|
||||
req,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { cache } from 'react'
|
||||
|
||||
type CachedValue = object
|
||||
|
||||
// Module-scoped cache container that holds all cached, stable containers
|
||||
// - these may hold the stable value, or a promise to the stable value
|
||||
const globalCacheContainer: Record<
|
||||
string,
|
||||
<TValue extends object = CachedValue>(
|
||||
...args: unknown[]
|
||||
) => {
|
||||
value: null | Promise<TValue> | TValue
|
||||
}
|
||||
> = {}
|
||||
|
||||
/**
|
||||
* Creates a selective cache function that provides more control over React's request-level caching behavior.
|
||||
*
|
||||
* @param namespace - A namespace to group related cached values
|
||||
* @returns A function that manages cached values within the specified namespace
|
||||
*/
|
||||
export function selectiveCache<TValue extends object = CachedValue>(namespace: string) {
|
||||
// Create a stable namespace container if it doesn't exist
|
||||
if (!globalCacheContainer[namespace]) {
|
||||
globalCacheContainer[namespace] = cache((...args) => ({
|
||||
value: null,
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates a cached value for a specific key within the namespace
|
||||
*
|
||||
* @param key - The key to identify the cached value
|
||||
* @param factory - A function that produces the value if not cached
|
||||
* @returns The cached or newly created value
|
||||
*/
|
||||
const getCached = async (factory: () => Promise<TValue>, ...cacheArgs): Promise<TValue> => {
|
||||
const stableObjectFn = globalCacheContainer[namespace]
|
||||
const stableObject = stableObjectFn<TValue>(...cacheArgs)
|
||||
|
||||
if (
|
||||
stableObject?.value &&
|
||||
'then' in stableObject.value &&
|
||||
typeof stableObject.value?.then === 'function'
|
||||
) {
|
||||
return await stableObject.value
|
||||
}
|
||||
|
||||
stableObject.value = factory()
|
||||
|
||||
return await stableObject.value
|
||||
}
|
||||
|
||||
return {
|
||||
get: getCached,
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
MinimizeMaximizeIcon,
|
||||
NumberField,
|
||||
SetDocumentStepNav,
|
||||
toast,
|
||||
useConfig,
|
||||
useDocumentInfo,
|
||||
useLocale,
|
||||
@@ -16,6 +15,7 @@ import {
|
||||
} from '@payloadcms/ui'
|
||||
import { useSearchParams } from 'next/navigation.js'
|
||||
import * as React from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import './index.scss'
|
||||
import { LocaleSelector } from './LocaleSelector/index.js'
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
'use client'
|
||||
import type { OnConfirm } from '@payloadcms/ui'
|
||||
import type { User } from 'payload'
|
||||
|
||||
import { Button, ConfirmationModal, toast, useModal, useTranslation } from '@payloadcms/ui'
|
||||
@@ -14,46 +15,54 @@ export const ResetPreferences: React.FC<{
|
||||
const { openModal } = useModal()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const handleResetPreferences = useCallback(async () => {
|
||||
if (!user) {
|
||||
return
|
||||
}
|
||||
const handleResetPreferences: OnConfirm = useCallback(
|
||||
async ({ closeConfirmationModal, setConfirming }) => {
|
||||
if (!user) {
|
||||
setConfirming(false)
|
||||
closeConfirmationModal()
|
||||
return
|
||||
}
|
||||
|
||||
const stringifiedQuery = qs.stringify(
|
||||
{
|
||||
depth: 0,
|
||||
where: {
|
||||
user: {
|
||||
id: {
|
||||
equals: user.id,
|
||||
const stringifiedQuery = qs.stringify(
|
||||
{
|
||||
depth: 0,
|
||||
where: {
|
||||
user: {
|
||||
id: {
|
||||
equals: user.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ addQueryPrefix: true },
|
||||
)
|
||||
{ addQueryPrefix: true },
|
||||
)
|
||||
|
||||
try {
|
||||
const res = await fetch(`${apiRoute}/payload-preferences${stringifiedQuery}`, {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'DELETE',
|
||||
})
|
||||
try {
|
||||
const res = await fetch(`${apiRoute}/payload-preferences${stringifiedQuery}`, {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'DELETE',
|
||||
})
|
||||
|
||||
const json = await res.json()
|
||||
const message = json.message
|
||||
const json = await res.json()
|
||||
const message = json.message
|
||||
|
||||
if (res.ok) {
|
||||
toast.success(message)
|
||||
} else {
|
||||
toast.error(message)
|
||||
if (res.ok) {
|
||||
toast.success(message)
|
||||
} else {
|
||||
toast.error(message)
|
||||
}
|
||||
} catch (_err) {
|
||||
// swallow error
|
||||
} finally {
|
||||
setConfirming(false)
|
||||
closeConfirmationModal()
|
||||
}
|
||||
} catch (_err) {
|
||||
// swallow error
|
||||
}
|
||||
}, [apiRoute, user])
|
||||
},
|
||||
[apiRoute, user],
|
||||
)
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { sanitizeID } from '@payloadcms/ui/shared'
|
||||
import {
|
||||
combineQueries,
|
||||
extractAccessFromPermission,
|
||||
type Payload,
|
||||
type SanitizedCollectionConfig,
|
||||
type SanitizedDocumentPermissions,
|
||||
type SanitizedGlobalConfig,
|
||||
type TypedUser,
|
||||
import type {
|
||||
Payload,
|
||||
SanitizedCollectionConfig,
|
||||
SanitizedDocumentPermissions,
|
||||
SanitizedGlobalConfig,
|
||||
TypedUser,
|
||||
} from 'payload'
|
||||
|
||||
import { sanitizeID } from '@payloadcms/ui/shared'
|
||||
|
||||
type Args = {
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
/**
|
||||
@@ -135,18 +134,15 @@ export const getVersions = async ({
|
||||
autosave: true,
|
||||
},
|
||||
user,
|
||||
where: combineQueries(
|
||||
{
|
||||
and: [
|
||||
{
|
||||
parent: {
|
||||
equals: id,
|
||||
},
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
parent: {
|
||||
equals: id,
|
||||
},
|
||||
],
|
||||
},
|
||||
extractAccessFromPermission(docPermissions.readVersions),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
if (
|
||||
@@ -162,28 +158,25 @@ export const getVersions = async ({
|
||||
;({ totalDocs: unpublishedVersionCount } = await payload.countVersions({
|
||||
collection: collectionConfig.slug,
|
||||
user,
|
||||
where: combineQueries(
|
||||
{
|
||||
and: [
|
||||
{
|
||||
parent: {
|
||||
equals: id,
|
||||
},
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
parent: {
|
||||
equals: id,
|
||||
},
|
||||
{
|
||||
'version._status': {
|
||||
equals: 'draft',
|
||||
},
|
||||
},
|
||||
{
|
||||
'version._status': {
|
||||
equals: 'draft',
|
||||
},
|
||||
{
|
||||
updatedAt: {
|
||||
greater_than: publishedDoc.updatedAt,
|
||||
},
|
||||
},
|
||||
{
|
||||
updatedAt: {
|
||||
greater_than: publishedDoc.updatedAt,
|
||||
},
|
||||
],
|
||||
},
|
||||
extractAccessFromPermission(docPermissions.readVersions),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -192,18 +185,15 @@ export const getVersions = async ({
|
||||
collection: collectionConfig.slug,
|
||||
depth: 0,
|
||||
user,
|
||||
where: combineQueries(
|
||||
{
|
||||
and: [
|
||||
{
|
||||
parent: {
|
||||
equals: id,
|
||||
},
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
parent: {
|
||||
equals: id,
|
||||
},
|
||||
],
|
||||
},
|
||||
extractAccessFromPermission(docPermissions.readVersions),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -252,23 +242,20 @@ export const getVersions = async ({
|
||||
depth: 0,
|
||||
global: globalConfig.slug,
|
||||
user,
|
||||
where: combineQueries(
|
||||
{
|
||||
and: [
|
||||
{
|
||||
'version._status': {
|
||||
equals: 'draft',
|
||||
},
|
||||
where: {
|
||||
and: [
|
||||
{
|
||||
'version._status': {
|
||||
equals: 'draft',
|
||||
},
|
||||
{
|
||||
updatedAt: {
|
||||
greater_than: publishedDoc.updatedAt,
|
||||
},
|
||||
},
|
||||
{
|
||||
updatedAt: {
|
||||
greater_than: publishedDoc.updatedAt,
|
||||
},
|
||||
],
|
||||
},
|
||||
extractAccessFromPermission(docPermissions.readVersions),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@ export const NotFoundPage = async ({
|
||||
redirectUnauthenticatedUser: true,
|
||||
route: formatAdminURL({ adminRoute, path: '/not-found' }),
|
||||
searchParams,
|
||||
useLayoutReq: true,
|
||||
})
|
||||
|
||||
const params = await paramsPromise
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
'use client'
|
||||
import type { OnConfirm } from '@payloadcms/ui'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import {
|
||||
Button,
|
||||
ConfirmationModal,
|
||||
PopupList,
|
||||
toast,
|
||||
useConfig,
|
||||
useModal,
|
||||
useRouteTransition,
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { formatAdminURL, requests } from '@payloadcms/ui/shared'
|
||||
import { useRouter } from 'next/navigation.js'
|
||||
import React, { Fragment, useCallback, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import type { Props } from './types.js'
|
||||
|
||||
@@ -74,21 +75,27 @@ const Restore: React.FC<Props> = ({
|
||||
})
|
||||
}
|
||||
|
||||
const handleRestore = useCallback(async () => {
|
||||
const res = await requests.post(fetchURL, {
|
||||
headers: {
|
||||
'Accept-Language': i18n.language,
|
||||
},
|
||||
})
|
||||
const handleRestore: OnConfirm = useCallback(
|
||||
async ({ closeConfirmationModal, setConfirming }) => {
|
||||
const res = await requests.post(fetchURL, {
|
||||
headers: {
|
||||
'Accept-Language': i18n.language,
|
||||
},
|
||||
})
|
||||
|
||||
if (res.status === 200) {
|
||||
const json = await res.json()
|
||||
toast.success(json.message)
|
||||
return startRouteTransition(() => router.push(redirectURL))
|
||||
} else {
|
||||
toast.error(t('version:problemRestoringVersion'))
|
||||
}
|
||||
}, [fetchURL, redirectURL, t, i18n, router, startRouteTransition])
|
||||
setConfirming(false)
|
||||
closeConfirmationModal()
|
||||
|
||||
if (res.status === 200) {
|
||||
const json = await res.json()
|
||||
toast.success(json.message)
|
||||
startRouteTransition(() => router.push(redirectURL))
|
||||
} else {
|
||||
toast.error(t('version:problemRestoringVersion'))
|
||||
}
|
||||
},
|
||||
[fetchURL, redirectURL, t, i18n, router, startRouteTransition],
|
||||
)
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/payload-cloud",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "The official Payload Cloud plugin",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "3.24.0",
|
||||
"version": "3.23.0",
|
||||
"description": "Node, React, Headless CMS and Application Framework built on Next.js",
|
||||
"keywords": [
|
||||
"admin panel",
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import type { AccessResult } from '../config/types.js'
|
||||
import type { Permission } from './index.js'
|
||||
|
||||
export const extractAccessFromPermission = (hasPermission: boolean | Permission): AccessResult => {
|
||||
if (typeof hasPermission === 'boolean') {
|
||||
return hasPermission
|
||||
}
|
||||
|
||||
const { permission, where } = hasPermission
|
||||
if (!permission) {
|
||||
return false
|
||||
}
|
||||
if (where && typeof where === 'object') {
|
||||
return where
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -54,8 +54,6 @@ async function autoLogin({
|
||||
await payload.find({
|
||||
collection: collection.config.slug,
|
||||
depth: isGraphQL ? 0 : collection.config.auth.depth,
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
where,
|
||||
})
|
||||
).docs[0]
|
||||
|
||||
@@ -76,18 +76,8 @@ export const bin = async () => {
|
||||
|
||||
if (userBinScript) {
|
||||
try {
|
||||
const module = await import(pathToFileURL(userBinScript.scriptPath).toString())
|
||||
|
||||
if (!module.script || typeof module.script !== 'function') {
|
||||
console.error(
|
||||
`Could not find "script" function export for script ${userBinScript.key} in ${userBinScript.scriptPath}`,
|
||||
)
|
||||
} else {
|
||||
await module.script(config).catch((err: unknown) => {
|
||||
console.log(`Script ${userBinScript.key} failed, details:`)
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
const script: BinScript = await import(pathToFileURL(userBinScript.scriptPath).toString())
|
||||
await script(config)
|
||||
} catch (err) {
|
||||
console.log(`Could not find associated bin script for the ${userBinScript.key} command`)
|
||||
console.error(err)
|
||||
|
||||
@@ -7,47 +7,17 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { countOperation } from '../count.js'
|
||||
|
||||
export type Options<TSlug extends CollectionSlug> = {
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, errors will not be thrown.
|
||||
*/
|
||||
disableErrors?: boolean
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
/**
|
||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||
*/
|
||||
where?: Where
|
||||
}
|
||||
|
||||
|
||||
@@ -7,47 +7,17 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { countVersionsOperation } from '../countVersions.js'
|
||||
|
||||
export type Options<TSlug extends CollectionSlug> = {
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, errors will not be thrown.
|
||||
*/
|
||||
disableErrors?: boolean
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
/**
|
||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||
*/
|
||||
where?: Where
|
||||
}
|
||||
|
||||
|
||||
@@ -26,92 +26,27 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { createOperation } from '../create.js'
|
||||
|
||||
export type Options<TSlug extends CollectionSlug, TSelect extends SelectType> = {
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* The data for the document to create.
|
||||
*/
|
||||
data: RequiredDataFromCollectionSlug<TSlug>
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, a [database transactions](https://payloadcms.com/docs/database/transactions) will not be initialized.
|
||||
* @default false
|
||||
*/
|
||||
disableTransaction?: boolean
|
||||
/**
|
||||
* If creating verification-enabled auth doc,
|
||||
* you can disable the email that is auto-sent
|
||||
*/
|
||||
disableVerificationEmail?: boolean
|
||||
/**
|
||||
* Create a **draft** document. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
|
||||
*/
|
||||
draft?: boolean
|
||||
/**
|
||||
* If you want to create a document that is a duplicate of another document
|
||||
*/
|
||||
duplicateFromID?: DataFromCollectionSlug<TSlug>['id']
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* A `File` object when creating a collection with `upload: true`.
|
||||
*/
|
||||
file?: File
|
||||
/**
|
||||
* A file path when creating a collection with `upload: true`.
|
||||
*/
|
||||
filePath?: string
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* If you are uploading a file and would like to replace
|
||||
* the existing file instead of generating a new filename,
|
||||
* you can set the following property to `true`
|
||||
*/
|
||||
overwriteExistingFiles?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: TSelect
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
|
||||
@@ -16,66 +16,21 @@ import { deleteOperation } from '../delete.js'
|
||||
import { deleteByIDOperation } from '../deleteByID.js'
|
||||
|
||||
export type BaseOptions<TSlug extends CollectionSlug, TSelect extends SelectType> = {
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, a [database transactions](https://payloadcms.com/docs/database/transactions) will not be initialized.
|
||||
* @default false
|
||||
*/
|
||||
disableTransaction?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* By default, document locks are ignored (`true`). Set to `false` to enforce locks and prevent operations when a document is locked by another user. [More details](https://payloadcms.com/docs/admin/locked-documents).
|
||||
* @default true
|
||||
*/
|
||||
overrideLock?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: TSelect
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
@@ -83,13 +38,7 @@ export type ByIDOptions<
|
||||
TSlug extends CollectionSlug,
|
||||
TSelect extends SelectFromCollectionSlug<TSlug>,
|
||||
> = {
|
||||
/**
|
||||
* The ID of the document to delete.
|
||||
*/
|
||||
id: number | string
|
||||
/**
|
||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||
*/
|
||||
where?: never
|
||||
} & BaseOptions<TSlug, TSelect>
|
||||
|
||||
@@ -97,13 +46,7 @@ export type ManyOptions<
|
||||
TSlug extends CollectionSlug,
|
||||
TSelect extends SelectFromCollectionSlug<TSlug>,
|
||||
> = {
|
||||
/**
|
||||
* The ID of the document to delete.
|
||||
*/
|
||||
id?: never
|
||||
/**
|
||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||
*/
|
||||
where: Where
|
||||
} & BaseOptions<TSlug, TSelect>
|
||||
|
||||
|
||||
@@ -20,73 +20,23 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { duplicateOperation } from '../duplicate.js'
|
||||
|
||||
export type Options<TSlug extends CollectionSlug, TSelect extends SelectType> = {
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* Override the data for the document to duplicate.
|
||||
*/
|
||||
data?: DeepPartial<RequiredDataFromCollectionSlug<TSlug>>
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, a [database transactions](https://payloadcms.com/docs/database/transactions) will not be initialized.
|
||||
* @default false
|
||||
*/
|
||||
disableTransaction?: boolean
|
||||
/**
|
||||
* Create a **draft** document. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
|
||||
*/
|
||||
draft?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* The ID of the document to duplicate from.
|
||||
*/
|
||||
id: number | string
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: TSelect
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
|
||||
@@ -23,104 +23,29 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { findOperation } from '../find.js'
|
||||
|
||||
export type Options<TSlug extends CollectionSlug, TSelect extends SelectType> = {
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* The current population depth, used internally for relationships population.
|
||||
* @internal
|
||||
*/
|
||||
currentDepth?: number
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, errors will not be thrown.
|
||||
*/
|
||||
disableErrors?: boolean
|
||||
/**
|
||||
* Whether the documents should be queried from the versions table/collection or not. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
|
||||
*/
|
||||
draft?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* Include info about the lock status to the result into all documents with fields: `_isLocked` and `_userEditing`
|
||||
*/
|
||||
includeLockStatus?: boolean
|
||||
/**
|
||||
* The [Join Field Query](https://payloadcms.com/docs/fields/join#query-options).
|
||||
* Pass `false` to disable all join fields from the result.
|
||||
*/
|
||||
joins?: JoinQuery<TSlug>
|
||||
/**
|
||||
* The maximum related documents to be returned.
|
||||
* Defaults unless `defaultLimit` is specified for the collection config
|
||||
* @default 10
|
||||
*/
|
||||
limit?: number
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: 'all' | TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* Get a specific page number
|
||||
* @default 1
|
||||
*/
|
||||
page?: number
|
||||
/**
|
||||
* Set to `false` to return all documents and avoid querying for document counts which introduces some overhead.
|
||||
* You can also combine that property with a specified `limit` to limit documents but avoid the count query.
|
||||
*/
|
||||
pagination?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: TSelect
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* Sort the documents, can be a string or an array of strings
|
||||
* @example '-createdAt' // Sort DESC by createdAt
|
||||
* @example ['group', '-createdAt'] // sort by 2 fields, ASC group and DESC createdAt
|
||||
*/
|
||||
sort?: Sort
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
/**
|
||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||
*/
|
||||
where?: Where
|
||||
}
|
||||
|
||||
|
||||
@@ -26,83 +26,25 @@ export type Options<
|
||||
TDisableErrors extends boolean,
|
||||
TSelect extends SelectType,
|
||||
> = {
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* The current population depth, used internally for relationships population.
|
||||
* @internal
|
||||
*/
|
||||
currentDepth?: number
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, errors will not be thrown.
|
||||
* `null` will be returned instead, if the document on this ID was not found.
|
||||
*/
|
||||
disableErrors?: TDisableErrors
|
||||
/**
|
||||
* Whether the document should be queried from the versions table/collection or not. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
|
||||
*/
|
||||
draft?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* The ID of the document to find.
|
||||
*/
|
||||
id: number | string
|
||||
/**
|
||||
* Include info about the lock status to the result with fields: `_isLocked` and `_userEditing`
|
||||
*/
|
||||
includeLockStatus?: boolean
|
||||
/**
|
||||
* The [Join Field Query](https://payloadcms.com/docs/fields/join#query-options).
|
||||
* Pass `false` to disable all join fields from the result.
|
||||
*/
|
||||
joins?: JoinQuery<TSlug>
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: 'all' | TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: TSelect
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
|
||||
@@ -9,69 +9,22 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { findVersionByIDOperation } from '../findVersionByID.js'
|
||||
|
||||
export type Options<TSlug extends CollectionSlug> = {
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, errors will not be thrown.
|
||||
* `null` will be returned instead, if the document on this ID was not found.
|
||||
*/
|
||||
disableErrors?: boolean
|
||||
/**
|
||||
* Whether the document should be queried from the versions table/collection or not. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
|
||||
*/
|
||||
draft?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* The ID of the version to find.
|
||||
*/
|
||||
id: string
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: 'all' | TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: SelectType
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
|
||||
@@ -17,81 +17,24 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { findVersionsOperation } from '../findVersions.js'
|
||||
|
||||
export type Options<TSlug extends CollectionSlug> = {
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* Whether the documents should be queried from the versions table/collection or not. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
|
||||
*/
|
||||
draft?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* The maximum related documents to be returned.
|
||||
* Defaults unless `defaultLimit` is specified for the collection config
|
||||
* @default 10
|
||||
*/
|
||||
limit?: number
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: 'all' | TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* Get a specific page number
|
||||
* @default 1
|
||||
*/
|
||||
page?: number
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: SelectType
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* Sort the documents, can be a string or an array of strings
|
||||
* @example '-version.createdAt' // Sort DESC by createdAt
|
||||
* @example ['version.group', '-version.createdAt'] // sort by 2 fields, ASC group and DESC createdAt
|
||||
*/
|
||||
sort?: Sort
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
/**
|
||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||
*/
|
||||
where?: Where
|
||||
}
|
||||
|
||||
|
||||
@@ -8,64 +8,21 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { restoreVersionOperation } from '../restoreVersion.js'
|
||||
|
||||
export type Options<TSlug extends CollectionSlug> = {
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* Whether the document should be queried from the versions table/collection or not. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
|
||||
*/
|
||||
draft?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* The ID of the version to restore.
|
||||
*/
|
||||
id: string
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: SelectType
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
|
||||
@@ -24,97 +24,28 @@ import { updateOperation } from '../update.js'
|
||||
import { updateByIDOperation } from '../updateByID.js'
|
||||
|
||||
export type BaseOptions<TSlug extends CollectionSlug, TSelect extends SelectType> = {
|
||||
/**
|
||||
* Whether the current update should be marked as from autosave.
|
||||
* `versions.drafts.autosave` should be specified.
|
||||
*/
|
||||
autosave?: boolean
|
||||
/**
|
||||
* the Collection slug to operate against.
|
||||
*/
|
||||
collection: TSlug
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* The document / documents data to update.
|
||||
*/
|
||||
data: DeepPartial<RequiredDataFromCollectionSlug<TSlug>>
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, a [database transactions](https://payloadcms.com/docs/database/transactions) will not be initialized.
|
||||
* @default false
|
||||
*/
|
||||
disableTransaction?: boolean
|
||||
/**
|
||||
* Update documents to a draft.
|
||||
*/
|
||||
draft?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* A `File` object when updating a collection with `upload: true`.
|
||||
*/
|
||||
file?: File
|
||||
/**
|
||||
* A file path when creating a collection with `upload: true`.
|
||||
*/
|
||||
filePath?: string
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* By default, document locks are ignored (`true`). Set to `false` to enforce locks and prevent operations when a document is locked by another user. [More details](https://payloadcms.com/docs/admin/locked-documents).
|
||||
* @default true
|
||||
*/
|
||||
overrideLock?: boolean
|
||||
/**
|
||||
* If you are uploading a file and would like to replace
|
||||
* the existing file instead of generating a new filename,
|
||||
* you can set the following property to `true`
|
||||
*/
|
||||
overwriteExistingFiles?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* Publish the document / documents with a specific locale.
|
||||
*/
|
||||
publishSpecificLocale?: string
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: TSelect
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
@@ -122,17 +53,8 @@ export type ByIDOptions<
|
||||
TSlug extends CollectionSlug,
|
||||
TSelect extends SelectFromCollectionSlug<TSlug>,
|
||||
> = {
|
||||
/**
|
||||
* The ID of the document to update.
|
||||
*/
|
||||
id: number | string
|
||||
/**
|
||||
* Limit documents to update
|
||||
*/
|
||||
limit?: never
|
||||
/**
|
||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||
*/
|
||||
where?: never
|
||||
} & BaseOptions<TSlug, TSelect>
|
||||
|
||||
@@ -140,17 +62,8 @@ export type ManyOptions<
|
||||
TSlug extends CollectionSlug,
|
||||
TSelect extends SelectFromCollectionSlug<TSlug>,
|
||||
> = {
|
||||
/**
|
||||
* The ID of the document to update.
|
||||
*/
|
||||
id?: never
|
||||
/**
|
||||
* Limit documents to update
|
||||
*/
|
||||
limit?: number
|
||||
/**
|
||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||
*/
|
||||
where: Where
|
||||
} & BaseOptions<TSlug, TSelect>
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { lt } from '@payloadcms/translations/languages/lt'
|
||||
@@ -107,13 +107,9 @@ export const createClientBlocks = ({
|
||||
clientBlock.imageURL = block.imageURL
|
||||
}
|
||||
|
||||
if (block.admin?.custom || block.admin?.group) {
|
||||
clientBlock.admin = {}
|
||||
if (block.admin.custom) {
|
||||
clientBlock.admin.custom = block.admin.custom
|
||||
}
|
||||
if (block.admin.group) {
|
||||
clientBlock.admin.group = block.admin.group
|
||||
if (block.admin?.custom) {
|
||||
clientBlock.admin = {
|
||||
custom: block.admin.custom,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1045,13 +1045,6 @@ export type SelectField = {
|
||||
*/
|
||||
enumName?: DBIdentifierName
|
||||
hasMany?: boolean
|
||||
/** Customize generated GraphQL and Typescript schema names.
|
||||
* By default, it is bound to the collection.
|
||||
*
|
||||
* This is useful if you would like to generate a top level type to share amongst collections/fields.
|
||||
* **Note**: Top level types can collide, ensure they are unique amongst collections, arrays, groups, blocks, tabs.
|
||||
*/
|
||||
interfaceName?: string
|
||||
options: Option[]
|
||||
type: 'select'
|
||||
} & (
|
||||
@@ -1069,7 +1062,7 @@ export type SelectField = {
|
||||
export type SelectFieldClient = {
|
||||
admin?: AdminClient & Pick<SelectField['admin'], 'isClearable' | 'isSortable'>
|
||||
} & FieldBaseClient &
|
||||
Pick<SelectField, 'hasMany' | 'interfaceName' | 'options' | 'type'>
|
||||
Pick<SelectField, 'hasMany' | 'options' | 'type'>
|
||||
|
||||
type SharedRelationshipProperties = {
|
||||
filterOptions?: FilterOptions
|
||||
@@ -1276,13 +1269,6 @@ export type RadioField = {
|
||||
* Customize the DB enum name
|
||||
*/
|
||||
enumName?: DBIdentifierName
|
||||
/** Customize generated GraphQL and Typescript schema names.
|
||||
* By default, it is bound to the collection.
|
||||
*
|
||||
* This is useful if you would like to generate a top level type to share amongst collections/fields.
|
||||
* **Note**: Top level types can collide, ensure they are unique amongst collections, arrays, groups, blocks, tabs.
|
||||
*/
|
||||
interfaceName?: string
|
||||
options: Option[]
|
||||
type: 'radio'
|
||||
validate?: RadioFieldValidation
|
||||
@@ -1291,7 +1277,7 @@ export type RadioField = {
|
||||
export type RadioFieldClient = {
|
||||
admin?: AdminClient & Pick<RadioField['admin'], 'layout'>
|
||||
} & FieldBaseClient &
|
||||
Pick<RadioField, 'interfaceName' | 'options' | 'type'>
|
||||
Pick<RadioField, 'options' | 'type'>
|
||||
|
||||
type BlockFields = {
|
||||
[key: string]: any
|
||||
@@ -1373,7 +1359,6 @@ export type Block = {
|
||||
}
|
||||
/** Extension point to add your custom data. Available in server and client. */
|
||||
custom?: Record<string, any>
|
||||
group?: Record<string, string> | string
|
||||
jsx?: PayloadComponent
|
||||
}
|
||||
/** Extension point to add your custom data. Server only. */
|
||||
@@ -1402,7 +1387,7 @@ export type Block = {
|
||||
}
|
||||
|
||||
export type ClientBlock = {
|
||||
admin?: Pick<Block['admin'], 'custom' | 'group'>
|
||||
admin?: Pick<Block['admin'], 'custom'>
|
||||
fields: ClientField[]
|
||||
labels?: LabelsClient
|
||||
} & Pick<Block, 'imageAltText' | 'imageURL' | 'jsx' | 'slug'>
|
||||
|
||||
@@ -357,10 +357,10 @@ export const json: JSONFieldValidation = async (
|
||||
const ajv = new Ajv()
|
||||
|
||||
if (!ajv.validate(schema, value)) {
|
||||
return ajv.errorsText()
|
||||
return t(ajv.errorsText())
|
||||
}
|
||||
} catch (error) {
|
||||
return error.message
|
||||
return t(error.message)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -8,46 +8,16 @@ import { countGlobalVersionsOperation } from '../countGlobalVersions.js'
|
||||
|
||||
export type CountGlobalVersionsOptions<TSlug extends GlobalSlug> = {
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, errors will not be thrown.
|
||||
*/
|
||||
disableErrors?: boolean
|
||||
/**
|
||||
* the Global slug to operate against.
|
||||
*/
|
||||
global: TSlug
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
/**
|
||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||
*/
|
||||
where?: Where
|
||||
}
|
||||
|
||||
|
||||
@@ -14,64 +14,18 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { findOneOperation } from '../findOne.js'
|
||||
|
||||
export type Options<TSlug extends GlobalSlug, TSelect extends SelectType> = {
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* Whether the document should be queried from the versions table/collection or not. [More](https://payloadcms.com/docs/versions/drafts#draft-api)
|
||||
*/
|
||||
draft?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* Include info about the lock status to the result with fields: `_isLocked` and `_userEditing`
|
||||
*/
|
||||
includeLockStatus?: boolean
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: 'all' | TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: TSelect
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* the Global slug to operate against.
|
||||
*/
|
||||
slug: TSlug
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
|
||||
@@ -9,65 +9,18 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { findVersionByIDOperation } from '../findVersionByID.js'
|
||||
|
||||
export type Options<TSlug extends GlobalSlug> = {
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* When set to `true`, errors will not be thrown.
|
||||
* `null` will be returned instead, if the document on this ID was not found.
|
||||
*/
|
||||
disableErrors?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* The ID of the version to find.
|
||||
*/
|
||||
id: string
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: 'all' | TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: SelectType
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* the Global slug to operate against.
|
||||
*/
|
||||
slug: TSlug
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
|
||||
@@ -18,77 +18,20 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { findVersionsOperation } from '../findVersions.js'
|
||||
|
||||
export type Options<TSlug extends GlobalSlug> = {
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* The maximum related documents to be returned.
|
||||
* Defaults unless `defaultLimit` is specified for the collection config
|
||||
* @default 10
|
||||
*/
|
||||
limit?: number
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: 'all' | TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* Get a specific page number
|
||||
* @default 1
|
||||
*/
|
||||
page?: number
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: SelectType
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* the Global slug to operate against.
|
||||
*/
|
||||
slug: TSlug
|
||||
/**
|
||||
* Sort the documents, can be a string or an array of strings
|
||||
* @example '-version.createdAt' // Sort DESC by createdAt
|
||||
* @example ['version.group', '-version.createdAt'] // sort by 2 fields, ASC group and DESC createdAt
|
||||
*/
|
||||
sort?: Sort
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
/**
|
||||
* A filter [query](https://payloadcms.com/docs/queries/overview)
|
||||
*/
|
||||
where?: Where
|
||||
}
|
||||
|
||||
|
||||
@@ -9,56 +9,16 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { restoreVersionOperation } from '../restoreVersion.js'
|
||||
|
||||
export type Options<TSlug extends GlobalSlug> = {
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* The ID of the version to restore.
|
||||
*/
|
||||
id: string
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* the Global slug to operate against.
|
||||
*/
|
||||
slug: TSlug
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
|
||||
@@ -22,74 +22,20 @@ import { createLocalReq } from '../../../utilities/createLocalReq.js'
|
||||
import { updateOperation } from '../update.js'
|
||||
|
||||
export type Options<TSlug extends GlobalSlug, TSelect extends SelectType> = {
|
||||
/**
|
||||
* [Context](https://payloadcms.com/docs/hooks/context), which will then be passed to `context` and `req.context`,
|
||||
* which can be read by hooks. Useful if you want to pass additional information to the hooks which
|
||||
* shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook
|
||||
* to determine if it should run or not.
|
||||
*/
|
||||
context?: RequestContext
|
||||
/**
|
||||
* The global data to update.
|
||||
*/
|
||||
data: DeepPartial<Omit<DataFromGlobalSlug<TSlug>, 'id'>>
|
||||
/**
|
||||
* [Control auto-population](https://payloadcms.com/docs/queries/depth) of nested relationship and upload fields.
|
||||
*/
|
||||
depth?: number
|
||||
/**
|
||||
* Update documents to a draft.
|
||||
*/
|
||||
draft?: boolean
|
||||
/**
|
||||
* Specify a [fallback locale](https://payloadcms.com/docs/configuration/localization) to use for any returned documents.
|
||||
*/
|
||||
fallbackLocale?: false | TypedLocale
|
||||
/**
|
||||
* Specify [locale](https://payloadcms.com/docs/configuration/localization) for any returned documents.
|
||||
*/
|
||||
locale?: 'all' | TypedLocale
|
||||
/**
|
||||
* Skip access control.
|
||||
* Set to `false` if you want to respect Access Control for the operation, for example when fetching data for the fron-end.
|
||||
* @default true
|
||||
*/
|
||||
overrideAccess?: boolean
|
||||
/**
|
||||
* If you are uploading a file and would like to replace
|
||||
* the existing file instead of generating a new filename,
|
||||
* you can set the following property to `true`
|
||||
*/
|
||||
overrideLock?: boolean
|
||||
/**
|
||||
* Specify [populate](https://payloadcms.com/docs/queries/select#populate) to control which fields to include to the result from populated documents.
|
||||
*/
|
||||
populate?: PopulateType
|
||||
/**
|
||||
* Publish the document / documents with a specific locale.
|
||||
*/
|
||||
publishSpecificLocale?: TypedLocale
|
||||
/**
|
||||
* The `PayloadRequest` object. You can pass it to thread the current [transaction](https://payloadcms.com/docs/database/transactions), user and locale to the operation.
|
||||
* Recommended to pass when using the Local API from hooks, as usually you want to execute the operation within the current transaction.
|
||||
*/
|
||||
req?: Partial<PayloadRequest>
|
||||
/**
|
||||
* Specify [select](https://payloadcms.com/docs/queries/select) to control which fields to include to the result.
|
||||
*/
|
||||
select?: TSelect
|
||||
/**
|
||||
* Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config.
|
||||
* @default false
|
||||
*/
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* the Global slug to operate against.
|
||||
*/
|
||||
slug: TSlug
|
||||
/**
|
||||
* If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks.
|
||||
*/
|
||||
user?: Document
|
||||
}
|
||||
|
||||
|
||||
@@ -923,12 +923,8 @@ export const getPayload = async (
|
||||
try {
|
||||
const port = process.env.PORT || '3000'
|
||||
|
||||
const path = '/_next/webpack-hmr'
|
||||
// The __NEXT_ASSET_PREFIX env variable is set for both assetPrefix and basePath (tested in Next.js 15.1.6)
|
||||
const prefix = process.env.__NEXT_ASSET_PREFIX ?? ''
|
||||
|
||||
cached.ws = new WebSocket(
|
||||
process.env.PAYLOAD_HMR_URL_OVERRIDE ?? `ws://localhost:${port}${prefix}${path}`,
|
||||
`ws://localhost:${port}${process.env.NEXT_BASE_PATH ?? ''}/_next/webpack-hmr`,
|
||||
)
|
||||
|
||||
cached.ws.onmessage = (event) => {
|
||||
@@ -972,7 +968,6 @@ interface RequestContext {
|
||||
export interface DatabaseAdapter extends BaseDatabaseAdapter {}
|
||||
export type { Payload, RequestContext }
|
||||
export { executeAuthStrategies } from './auth/executeAuthStrategies.js'
|
||||
export { extractAccessFromPermission } from './auth/extractAccessFromPermission.js'
|
||||
export { getAccessResults } from './auth/getAccessResults.js'
|
||||
export { getFieldsToSign } from './auth/getFieldsToSign.js'
|
||||
export * from './auth/index.js'
|
||||
@@ -989,7 +984,6 @@ export { resetPasswordOperation } from './auth/operations/resetPassword.js'
|
||||
export { unlockOperation } from './auth/operations/unlock.js'
|
||||
export { verifyEmailOperation } from './auth/operations/verifyEmail.js'
|
||||
export { JWTAuthentication } from './auth/strategies/jwt.js'
|
||||
|
||||
export type {
|
||||
AuthStrategyFunction,
|
||||
AuthStrategyFunctionArgs,
|
||||
@@ -1010,8 +1004,8 @@ export type {
|
||||
} from './auth/types.js'
|
||||
|
||||
export { generateImportMap } from './bin/generateImportMap/index.js'
|
||||
export type { ImportMap } from './bin/generateImportMap/index.js'
|
||||
|
||||
export type { ImportMap } from './bin/generateImportMap/index.js'
|
||||
export { genImportMapIterateFields } from './bin/generateImportMap/iterateFields.js'
|
||||
|
||||
export {
|
||||
@@ -1058,6 +1052,7 @@ export type {
|
||||
TypeWithID,
|
||||
TypeWithTimestamps,
|
||||
} from './collections/config/types.js'
|
||||
|
||||
export { createDataloaderCacheKey, getDataLoader } from './collections/dataloader.js'
|
||||
export { countOperation } from './collections/operations/count.js'
|
||||
export { createOperation } from './collections/operations/create.js'
|
||||
@@ -1080,8 +1075,8 @@ export {
|
||||
serverOnlyConfigProperties,
|
||||
type UnsanitizedClientConfig,
|
||||
} from './config/client.js'
|
||||
|
||||
export { defaults } from './config/defaults.js'
|
||||
|
||||
export { sanitizeConfig } from './config/sanitize.js'
|
||||
export type * from './config/types.js'
|
||||
export { combineQueries } from './database/combineQueries.js'
|
||||
|
||||
@@ -11,7 +11,6 @@ export const validOperators = [
|
||||
'less_than',
|
||||
'less_than_equal',
|
||||
'like',
|
||||
'not_like',
|
||||
'within',
|
||||
'intersects',
|
||||
'near',
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { Stats } from 'fs'
|
||||
|
||||
// @ts-strict-ignore
|
||||
import { fileTypeFromFile } from 'file-type'
|
||||
import fsPromises from 'fs/promises'
|
||||
@@ -56,39 +54,7 @@ export const getFileHandler: PayloadHandler = async (req) => {
|
||||
|
||||
const fileDir = collection.config.upload?.staticDir || collection.config.slug
|
||||
const filePath = path.resolve(`${fileDir}/${filename}`)
|
||||
let stats: Stats
|
||||
|
||||
try {
|
||||
stats = await fsPromises.stat(filePath)
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
req.payload.logger.error(
|
||||
`File ${filename} for collection ${collection.config.slug} is missing on the disk. Expected path: ${filePath}`,
|
||||
)
|
||||
|
||||
// Omit going to the routeError handler by returning response instead of
|
||||
// throwing an error to cut down log noise. The response still matches what you get with APIError to not leak details to the user.
|
||||
return Response.json(
|
||||
{
|
||||
errors: [
|
||||
{
|
||||
message: 'Something went wrong.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
headers: headersWithCors({
|
||||
headers: new Headers(),
|
||||
req,
|
||||
}),
|
||||
status: 500,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
throw err
|
||||
}
|
||||
|
||||
const stats = await fsPromises.stat(filePath)
|
||||
const data = streamFile(filePath)
|
||||
const fileTypeResult = (await fileTypeFromFile(filePath)) || getFileTypeFallback(filePath)
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ export const checkDocumentLockStatus = async ({
|
||||
collection: 'payload-locked-documents',
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
//req,
|
||||
sort: '-updatedAt',
|
||||
where: lockedDocumentQuery,
|
||||
})
|
||||
@@ -92,8 +93,7 @@ export const checkDocumentLockStatus = async ({
|
||||
// Perform the delete operation regardless of overrideLock status
|
||||
await payload.db.deleteMany({
|
||||
collection: 'payload-locked-documents',
|
||||
// Not passing req fails on postgres
|
||||
req: payload.db.name === 'mongoose' ? undefined : req,
|
||||
req, //
|
||||
where: lockedDocumentQuery,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import type { SanitizedGlobalConfig } from '../globals/config/types.js'
|
||||
import { MissingEditorProp } from '../errors/MissingEditorProp.js'
|
||||
import { fieldAffectsData } from '../fields/config/types.js'
|
||||
import { generateJobsJSONSchemas } from '../queues/config/generateJobsJSONSchemas.js'
|
||||
import { deepCopyObject } from './deepCopyObject.js'
|
||||
import { toWords } from './formatLabels.js'
|
||||
import { getCollectionIDFieldTypes } from './getCollectionIDFieldTypes.js'
|
||||
|
||||
@@ -495,14 +496,6 @@ export function fieldsToJSONSchema(
|
||||
enum: buildOptionEnums(field.options),
|
||||
}
|
||||
|
||||
if (field.interfaceName) {
|
||||
interfaceNameDefinitions.set(field.interfaceName, fieldSchema)
|
||||
|
||||
fieldSchema = {
|
||||
$ref: `#/definitions/${field.interfaceName}`,
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
@@ -664,15 +657,6 @@ export function fieldsToJSONSchema(
|
||||
fieldSchema.enum = optionEnums
|
||||
}
|
||||
}
|
||||
|
||||
if (field.interfaceName) {
|
||||
interfaceNameDefinitions.set(field.interfaceName, fieldSchema)
|
||||
|
||||
fieldSchema = {
|
||||
$ref: `#/definitions/${field.interfaceName}`,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
break
|
||||
@@ -718,7 +702,7 @@ export function fieldsToJSONSchema(
|
||||
// This function is part of the public API and is exported through payload/utilities
|
||||
export function entityToJSONSchema(
|
||||
config: SanitizedConfig,
|
||||
entity: SanitizedCollectionConfig | SanitizedGlobalConfig,
|
||||
incomingEntity: SanitizedCollectionConfig | SanitizedGlobalConfig,
|
||||
interfaceNameDefinitions: Map<string, JSONSchema4>,
|
||||
defaultIDType: 'number' | 'text',
|
||||
collectionIDFieldTypes?: { [key: string]: 'number' | 'string' },
|
||||
@@ -728,30 +712,25 @@ export function entityToJSONSchema(
|
||||
collectionIDFieldTypes = getCollectionIDFieldTypes({ config, defaultIDType })
|
||||
}
|
||||
|
||||
const entity: SanitizedCollectionConfig | SanitizedGlobalConfig = deepCopyObject(incomingEntity)
|
||||
const title = entity.typescript?.interface
|
||||
? entity.typescript.interface
|
||||
: singular(toWords(entity.slug, true))
|
||||
|
||||
let mutableFields = [...entity.flattenedFields]
|
||||
|
||||
const idField: FieldAffectingData = { name: 'id', type: defaultIDType as 'text', required: true }
|
||||
const customIdField = mutableFields.find((field) => field.name === 'id') as FieldAffectingData
|
||||
const customIdField = entity.flattenedFields.find(
|
||||
(field) => field.name === 'id',
|
||||
) as FieldAffectingData
|
||||
|
||||
if (customIdField && customIdField.type !== 'group' && customIdField.type !== 'tab') {
|
||||
mutableFields = mutableFields.map((field) => {
|
||||
if (field === customIdField) {
|
||||
return { ...field, required: true }
|
||||
}
|
||||
|
||||
return field
|
||||
})
|
||||
customIdField.required = true
|
||||
} else {
|
||||
mutableFields.unshift(idField)
|
||||
entity.flattenedFields.unshift(idField)
|
||||
}
|
||||
|
||||
// mark timestamp fields required
|
||||
if ('timestamps' in entity && entity.timestamps !== false) {
|
||||
mutableFields = mutableFields.map((field) => {
|
||||
entity.flattenedFields = entity.flattenedFields.map((field) => {
|
||||
if (field.name === 'createdAt' || field.name === 'updatedAt') {
|
||||
return {
|
||||
...field,
|
||||
@@ -769,7 +748,7 @@ export function entityToJSONSchema(
|
||||
(typeof entity.auth?.disableLocalStrategy === 'object' &&
|
||||
entity.auth.disableLocalStrategy.enableFields))
|
||||
) {
|
||||
mutableFields.push({
|
||||
entity.flattenedFields.push({
|
||||
name: 'password',
|
||||
type: 'text',
|
||||
})
|
||||
@@ -781,7 +760,7 @@ export function entityToJSONSchema(
|
||||
title,
|
||||
...fieldsToJSONSchema(
|
||||
collectionIDFieldTypes,
|
||||
mutableFields,
|
||||
entity.flattenedFields,
|
||||
interfaceNameDefinitions,
|
||||
config,
|
||||
i18n,
|
||||
@@ -1156,43 +1135,40 @@ export function configToJSONSchema(
|
||||
)
|
||||
: {}
|
||||
|
||||
let blocksDefinition: JSONSchema4 | undefined = undefined
|
||||
if (config?.blocks?.length) {
|
||||
blocksDefinition = {
|
||||
const blocksDefinition: JSONSchema4 = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {},
|
||||
required: [],
|
||||
}
|
||||
for (const block of config.blocks) {
|
||||
const blockFieldSchemas = fieldsToJSONSchema(
|
||||
collectionIDFieldTypes,
|
||||
block.flattenedFields,
|
||||
interfaceNameDefinitions,
|
||||
config,
|
||||
i18n,
|
||||
)
|
||||
|
||||
const blockSchema: JSONSchema4 = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {},
|
||||
required: [],
|
||||
}
|
||||
for (const block of config.blocks) {
|
||||
const blockFieldSchemas = fieldsToJSONSchema(
|
||||
collectionIDFieldTypes,
|
||||
block.flattenedFields,
|
||||
interfaceNameDefinitions,
|
||||
config,
|
||||
i18n,
|
||||
)
|
||||
|
||||
const blockSchema: JSONSchema4 = {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
...blockFieldSchemas.properties,
|
||||
blockType: {
|
||||
const: block.slug,
|
||||
},
|
||||
properties: {
|
||||
...blockFieldSchemas.properties,
|
||||
blockType: {
|
||||
const: block.slug,
|
||||
},
|
||||
required: ['blockType', ...blockFieldSchemas.required],
|
||||
}
|
||||
|
||||
const interfaceName = block.interfaceName ?? block.slug
|
||||
interfaceNameDefinitions.set(interfaceName, blockSchema)
|
||||
|
||||
blocksDefinition.properties[block.slug] = {
|
||||
$ref: `#/definitions/${interfaceName}`,
|
||||
}
|
||||
;(blocksDefinition.required as string[]).push(block.slug)
|
||||
},
|
||||
required: ['blockType', ...blockFieldSchemas.required],
|
||||
}
|
||||
|
||||
const interfaceName = block.interfaceName ?? block.slug
|
||||
interfaceNameDefinitions.set(interfaceName, blockSchema)
|
||||
|
||||
blocksDefinition.properties[block.slug] = {
|
||||
$ref: `#/definitions/${interfaceName}`,
|
||||
}
|
||||
;(blocksDefinition.required as string[]).push(block.slug)
|
||||
}
|
||||
|
||||
let jsonSchema: JSONSchema4 = {
|
||||
@@ -1232,7 +1208,6 @@ export function configToJSONSchema(
|
||||
],
|
||||
title: 'Config',
|
||||
}
|
||||
|
||||
if (jobsSchemas.definitions?.size) {
|
||||
for (const [key, value] of jobsSchemas.definitions) {
|
||||
jsonSchema.definitions[key] = value
|
||||
|
||||
@@ -48,10 +48,7 @@ export async function getEntityPolicies<T extends Args>(args: T): Promise<Return
|
||||
|
||||
let docBeingAccessed: EntityDoc | Promise<EntityDoc | undefined> | undefined
|
||||
|
||||
async function getEntityDoc({
|
||||
operation,
|
||||
where,
|
||||
}: { operation?: AllOperations; where?: Where } = {}): Promise<EntityDoc | undefined> {
|
||||
async function getEntityDoc({ where }: { where?: Where } = {}): Promise<EntityDoc | undefined> {
|
||||
if (!entity.slug) {
|
||||
return undefined
|
||||
}
|
||||
@@ -69,28 +66,18 @@ export async function getEntityPolicies<T extends Args>(args: T): Promise<Return
|
||||
|
||||
if (type === 'collection' && id) {
|
||||
if (typeof where === 'object') {
|
||||
const options = {
|
||||
const paginatedRes = await payload.find({
|
||||
collection: entity.slug,
|
||||
depth: 0,
|
||||
fallbackLocale: null,
|
||||
limit: 1,
|
||||
locale,
|
||||
overrideAccess: true,
|
||||
req,
|
||||
}
|
||||
if (operation === 'readVersions') {
|
||||
const paginatedRes = await payload.findVersions({
|
||||
...options,
|
||||
where: combineQueries(where, { parent: { equals: id } }),
|
||||
})
|
||||
return paginatedRes?.docs?.[0] || undefined
|
||||
}
|
||||
|
||||
const paginatedRes = await payload.find({
|
||||
...options,
|
||||
pagination: false,
|
||||
req,
|
||||
where: combineQueries(where, { id: { equals: id } }),
|
||||
})
|
||||
|
||||
return paginatedRes?.docs?.[0] || undefined
|
||||
}
|
||||
|
||||
@@ -129,9 +116,7 @@ export async function getEntityPolicies<T extends Args>(args: T): Promise<Return
|
||||
if (typeof accessResult === 'object' && !disableWhere) {
|
||||
mutablePolicies[operation] = {
|
||||
permission:
|
||||
id || type === 'global'
|
||||
? !!(await getEntityDoc({ operation, where: accessResult }))
|
||||
: true,
|
||||
id || type === 'global' ? !!(await getEntityDoc({ where: accessResult })) : true,
|
||||
where: accessResult,
|
||||
}
|
||||
} else if (mutablePolicies[operation]?.permission !== false) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user