Compare commits
1 Commits
v1.11.8
...
feat/draft
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a77320841 |
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,29 +1,5 @@
|
||||
|
||||
|
||||
## [1.11.8](https://github.com/payloadcms/payload/compare/v1.11.7...v1.11.8) (2023-07-31)
|
||||
|
||||
## [1.11.7](https://github.com/payloadcms/payload/compare/v1.11.6...v1.11.7) (2023-07-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* [#3062](https://github.com/payloadcms/payload/issues/3062) ([0280953](https://github.com/payloadcms/payload/commit/02809532b484d9018c6528cfbbbb43abfd55a540))
|
||||
* array row deletion ([#3062](https://github.com/payloadcms/payload/issues/3062)) ([cf9795b](https://github.com/payloadcms/payload/commit/cf9795b8d8b53c48335ff4c32c6c51b3de4f7bc9))
|
||||
* incorrect image rotation after being processed by sharp ([#3081](https://github.com/payloadcms/payload/issues/3081)) ([0a91950](https://github.com/payloadcms/payload/commit/0a91950f052ce40427801e6561a0f676354a2ca4))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ability to add context to payload's request object ([#2796](https://github.com/payloadcms/payload/issues/2796)) ([67ba131](https://github.com/payloadcms/payload/commit/67ba131cc61f3d3b30ef9ef7fc150344ca82da2f))
|
||||
|
||||
## [1.11.6](https://github.com/payloadcms/payload/compare/v1.11.5...v1.11.6) (2023-07-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **collections:admin:** Enable adminThumbnail fn execution on all types ([2c74e93](https://github.com/payloadcms/payload/commit/2c74e9396a216a033e2bacdf189b7f28a0f97505))
|
||||
* threads hasMaxRows into ArrayAction components within blocks and arrays ([#3066](https://github.com/payloadcms/payload/issues/3066)) ([d43c83d](https://github.com/payloadcms/payload/commit/d43c83dad1bab5b05f4fcbae7d41de369905797c))
|
||||
|
||||
## [1.11.5](https://github.com/payloadcms/payload/compare/v1.11.4...v1.11.5) (2023-07-25)
|
||||
|
||||
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
---
|
||||
title: Context
|
||||
label: Context
|
||||
order: 50
|
||||
desc: Context allows you to pass in extra data that can be shared between hooks
|
||||
keywords: hooks, context, payload context, payloadcontext, data, extra data, shared data, shared, extra
|
||||
---
|
||||
|
||||
The `context` object in hooks is used to share data across different hooks. The persists throughout the entire lifecycle of a request and is available within every hook. This allows you to add logic to your hooks based on the request state by setting properties to `req.context` and using them elsewhere.
|
||||
|
||||
## When to use Context
|
||||
|
||||
Context gives you a way forward on otherwise difficult problems such as:
|
||||
|
||||
1. **Passing data between hooks**: Needing data in multiple hooks from a 3rd party API, it could be retrieved and used in `beforeChange` and later used again in an `afterChange` hook without having to fetch it twice.
|
||||
2. **Preventing infinite loops**: Calling `payload.update()` on the same document that triggered an `afterChange` hook will create an infinite loop, control the flow by assigning a no-op condition to context
|
||||
3. **Passing data to local API**: Setting values on the `req.context` and pass it to `payload.create()` you can provide additional data to hooks without adding extraneous fields.
|
||||
4. **Passing data between hooks and middleware or custom endpoints**: Hooks could set context across multiple collections and then be used in a final `postMiddleware`.
|
||||
|
||||
## How to Use Context
|
||||
|
||||
Let's see examples on how context can be used in the first two scenarios mentioned above:
|
||||
|
||||
### Passing data between hooks
|
||||
|
||||
To pass data between hooks, you can assign values to context in an earlier hook in the lifecycle of a request and expect it the context in a later hook.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
const Customer: CollectionConfig = {
|
||||
slug: 'customers',
|
||||
hooks: {
|
||||
beforeChange: [async ({ context, data }) => {
|
||||
// assign the customerData to context for use later
|
||||
context.customerData = await fetchCustomerData(data.customerID);
|
||||
return {
|
||||
...data,
|
||||
// some data we use here
|
||||
name: context.customerData.name
|
||||
};
|
||||
}],
|
||||
afterChange: [async ({ context, doc, req }) => {
|
||||
// use context.customerData without needing to fetch it again
|
||||
if (context.customerData.contacted === false) {
|
||||
createTodo('Call Customer', context.customerData)
|
||||
}
|
||||
}],
|
||||
},
|
||||
fields: [ /* ... */ ],
|
||||
};
|
||||
```
|
||||
|
||||
### Preventing infinite loops
|
||||
|
||||
Let's say you have an `afterChange` hook, and you want to do a calculation inside the hook (as the document ID needed for the calculation is available in the `afterChange` hook, but not in the `beforeChange` hook). Once that's done, you want to update the document with the result of the calculation.
|
||||
|
||||
Bad example:
|
||||
|
||||
```ts
|
||||
const Customer: CollectionConfig = {
|
||||
slug: 'customers',
|
||||
hooks: {
|
||||
afterChange: [async ({ doc }) => {
|
||||
await payload.update({
|
||||
// DANGER: updating the same slug as the collection in an afterChange will create an infinite loop!
|
||||
collection: 'customers',
|
||||
id: doc.id,
|
||||
data: {
|
||||
...(await fetchCustomerData(data.customerID))
|
||||
},
|
||||
});
|
||||
}],
|
||||
},
|
||||
fields: [ /* ... */ ],
|
||||
};
|
||||
```
|
||||
|
||||
Instead of the above, we need to tell the `afterChange` hook to not run again if it performs the update (and thus not update itself again). We can solve that with context.
|
||||
|
||||
Fixed example:
|
||||
|
||||
```ts
|
||||
const MyCollection: CollectionConfig = {
|
||||
slug: 'slug',
|
||||
hooks: {
|
||||
afterChange: [async ({ context, doc }) => {
|
||||
// return if flag was previously set
|
||||
if (context.triggerAfterChange === false) {
|
||||
return;
|
||||
}
|
||||
await payload.update({
|
||||
collection: contextHooksSlug,
|
||||
id: doc.id,
|
||||
data: {
|
||||
...(await fetchCustomerData(data.customerID))
|
||||
},
|
||||
context: {
|
||||
// set a flag to prevent from running again
|
||||
triggerAfterChange: false,
|
||||
},
|
||||
});
|
||||
}],
|
||||
},
|
||||
fields: [ /* ... */ ],
|
||||
};
|
||||
```
|
||||
|
||||
## Typing context
|
||||
|
||||
The default typescript interface for `context` is `{ [key: string]: unknown }`. If you prefer a more strict typing in your project or when authoring plugins for others, you can override this using the `declare` syntax.
|
||||
|
||||
This is known as "type augmentation" - a TypeScript feature which allows us to add types to existing objects. Simply put this in any .ts or .d.ts file:
|
||||
|
||||
```ts
|
||||
import { RequestContext as OriginalRequestContext } from 'payload';
|
||||
|
||||
declare module 'payload' {
|
||||
// Create a new interface that merges your additional fields with the original one
|
||||
export interface RequestContext extends OriginalRequestContext {
|
||||
myObject?: string;
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This will add a the property `myObject` with a type of string to every context object. Make sure to follow this example correctly, as type augmentation can mess up your types if you do it wrong.
|
||||
@@ -77,7 +77,6 @@ You can specify more options within the Local API vs. REST or GraphQL due to the
|
||||
| `user` | If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks. |
|
||||
| `showHiddenFields` | Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config. |
|
||||
| `pagination` | Set to false to return all documents and avoid querying for document counts. |
|
||||
| `context` | [Context](/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. |
|
||||
|
||||
_There are more options available on an operation by operation basis outlined below._
|
||||
|
||||
|
||||
@@ -190,7 +190,9 @@ export const Media: CollectionConfig = {
|
||||
<Banner>
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
This function runs in the browser. If your function returns `null` or `false` Payload will show the default generic file thumbnail instead.
|
||||
If you specify a function to return an admin thumbnail, but your upload is not
|
||||
an image file type (for example, PDF or TXT) your function will not be used.
|
||||
Instead, Payload will display its generic file upload graphic.
|
||||
</Banner>
|
||||
|
||||
### MimeTypes
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"dependencies": {
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"payload": "latest"
|
||||
"payload": "^1.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@payloadcms/eslint-config": "^0.0.1",
|
||||
@@ -42,4 +42,4 @@
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "payload-nextjs-auth-example-app",
|
||||
"name": "payload-nextjs-auth-example",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "payload-nextjs-auth-example-pages",
|
||||
"name": "payload-nextjs-auth-example",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "next dev -p 3001",
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"escape-html": "^1.0.3",
|
||||
"express": "^4.17.1",
|
||||
"next": "^13.4.8",
|
||||
"payload": "latest",
|
||||
"payload": "^1.8.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
@@ -52,4 +52,4 @@
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@
|
||||
"dependencies": {
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"payload": "latest",
|
||||
"payload": "1.6.29",
|
||||
"handlebars": "^4.7.7",
|
||||
"inline-css": "^4.0.2"
|
||||
},
|
||||
@@ -32,4 +32,4 @@
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "payload-example-form-builder-cms",
|
||||
"name": "form-builder-example-cms",
|
||||
"description": "The CMS that utilizes Payload's form builder plugin.",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/server.js",
|
||||
@@ -20,7 +20,7 @@
|
||||
"@payloadcms/plugin-seo": "^1.0.8",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"payload": "latest"
|
||||
"payload": "^1.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.9",
|
||||
@@ -30,4 +30,4 @@
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.1.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "payload-example-form-builder-website",
|
||||
"name": "form-builder-example-website",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"dependencies": {
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"payload": "latest"
|
||||
"payload": "^1.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@payloadcms/eslint-config": "^0.0.1",
|
||||
@@ -43,4 +43,4 @@
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,7 @@
|
||||
"dependencies": {
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"payload": "latest"
|
||||
"payload": "^1.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@payloadcms/eslint-config": "^0.0.2",
|
||||
@@ -43,4 +43,4 @@
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "payload-example-nextjs-preview-app",
|
||||
"name": "payload-nextjs-preview-example",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "payload-example-nextjs-preview-pages",
|
||||
"name": "payload-nextjs-preview-example",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "payload-example-redirects-cms",
|
||||
"name": "redirects-example-cms",
|
||||
"description": "The CMS is used to demonstrate the redirects feature.",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/server.js",
|
||||
@@ -20,7 +20,7 @@
|
||||
"@payloadcms/plugin-redirects": "^1.0.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"payload": "latest"
|
||||
"payload": "^1.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@payloadcms/eslint-config": "^0.0.1",
|
||||
@@ -43,4 +43,4 @@
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "payload-example-nextjs-redirects-pages",
|
||||
"name": "nextjs-redirects-example",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "payload-example-virtual-fields-cms",
|
||||
"name": "virtual-fields",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/server.js",
|
||||
"license": "MIT",
|
||||
@@ -16,7 +16,7 @@
|
||||
"dependencies": {
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"payload": "latest"
|
||||
"payload": "^1.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.9",
|
||||
@@ -26,4 +26,4 @@
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "payload-example-whitelabel-cms",
|
||||
"name": "whitelabel-example-cms",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/server.js",
|
||||
"license": "MIT",
|
||||
@@ -16,7 +16,7 @@
|
||||
"dependencies": {
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"payload": "latest"
|
||||
"payload": "^1.7.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.9",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "1.11.8",
|
||||
"version": "1.11.5",
|
||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -96,7 +96,6 @@
|
||||
"compression": "^1.7.4",
|
||||
"conf": "^10.2.0",
|
||||
"connect-history-api-fallback": "^1.6.0",
|
||||
"console-table-printer": "^2.11.2",
|
||||
"css-loader": "^5.2.7",
|
||||
"css-minimizer-webpack-plugin": "^5.0.0",
|
||||
"dataloader": "^2.1.0",
|
||||
|
||||
@@ -19,7 +19,6 @@ export const ArrayAction: React.FC<Props> = ({
|
||||
addRow,
|
||||
duplicateRow,
|
||||
removeRow,
|
||||
hasMaxRows,
|
||||
}) => {
|
||||
const { t } = useTranslation('general');
|
||||
return (
|
||||
@@ -57,32 +56,28 @@ export const ArrayAction: React.FC<Props> = ({
|
||||
{t('moveDown')}
|
||||
</button>
|
||||
)}
|
||||
{!hasMaxRows && (
|
||||
<React.Fragment>
|
||||
<button
|
||||
className={`${baseClass}__action ${baseClass}__add`}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
addRow(index);
|
||||
close();
|
||||
}}
|
||||
>
|
||||
<Plus />
|
||||
{t('addBelow')}
|
||||
</button>
|
||||
<button
|
||||
className={`${baseClass}__action ${baseClass}__duplicate`}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
duplicateRow(index);
|
||||
close();
|
||||
}}
|
||||
>
|
||||
<Copy />
|
||||
{t('duplicate')}
|
||||
</button>
|
||||
</React.Fragment>
|
||||
)}
|
||||
<button
|
||||
className={`${baseClass}__action ${baseClass}__add`}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
addRow(index);
|
||||
close();
|
||||
}}
|
||||
>
|
||||
<Plus />
|
||||
{t('addBelow')}
|
||||
</button>
|
||||
<button
|
||||
className={`${baseClass}__action ${baseClass}__duplicate`}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
duplicateRow(index);
|
||||
close();
|
||||
}}
|
||||
>
|
||||
<Copy />
|
||||
{t('duplicate')}
|
||||
</button>
|
||||
<button
|
||||
className={`${baseClass}__action ${baseClass}__remove`}
|
||||
type="button"
|
||||
|
||||
@@ -5,5 +5,4 @@ export type Props = {
|
||||
moveRow: (from: number, to: number) => void
|
||||
index: number
|
||||
rowCount: number
|
||||
hasMaxRows: boolean
|
||||
}
|
||||
|
||||
@@ -6,6 +6,11 @@ import { FormField, FieldAction, Fields } from './types';
|
||||
import deepCopyObject from '../../../../utilities/deepCopyObject';
|
||||
import { flattenRows, separateRows } from './rows';
|
||||
|
||||
function splitPathByArrayFields(str) {
|
||||
const regex = /\.(\d+)\./g;
|
||||
return str.split(regex).filter(Boolean);
|
||||
}
|
||||
|
||||
export function fieldReducer(state: Fields, action: FieldAction): Fields {
|
||||
switch (action.type) {
|
||||
case 'REPLACE_STATE': {
|
||||
|
||||
@@ -29,7 +29,6 @@ type ArrayRowProps = UseDraggableSortableReturn & Pick<Props, 'fields' | 'path'
|
||||
row: Row
|
||||
CustomRowLabel?: RowLabelType
|
||||
readOnly?: boolean
|
||||
hasMaxRows?: boolean
|
||||
}
|
||||
export const ArrayRow: React.FC<ArrayRowProps> = ({
|
||||
path: parentPath,
|
||||
@@ -52,7 +51,6 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
|
||||
permissions,
|
||||
CustomRowLabel,
|
||||
fields,
|
||||
hasMaxRows,
|
||||
}) => {
|
||||
const path = `${parentPath}.${rowIndex}`;
|
||||
const { i18n } = useTranslation();
|
||||
@@ -110,7 +108,6 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
|
||||
duplicateRow={duplicateRow}
|
||||
rowCount={rowCount}
|
||||
index={rowIndex}
|
||||
hasMaxRows={hasMaxRows}
|
||||
/>
|
||||
) : undefined}
|
||||
>
|
||||
|
||||
@@ -95,7 +95,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
showError,
|
||||
errorMessage,
|
||||
value,
|
||||
rows = [],
|
||||
rows,
|
||||
valid,
|
||||
} = useField<number>({
|
||||
path,
|
||||
@@ -142,8 +142,8 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
dispatchFields({ type: 'SET_ROW_COLLAPSED', path, collapsed, rowID, setDocFieldPreferences });
|
||||
}, [dispatchFields, path, setDocFieldPreferences]);
|
||||
|
||||
const hasMaxRows = maxRows && rows.length >= maxRows;
|
||||
const fieldErrorCount = rows.reduce((total, row) => total + (row?.childErrorPaths?.size || 0), 0) + (valid ? 0 : 1);
|
||||
const hasMaxRows = maxRows && rows?.length >= maxRows;
|
||||
const fieldErrorCount = (rows || []).reduce((total, row) => total + (row?.childErrorPaths?.size || 0), 0) + (valid ? 0 : 1);
|
||||
const fieldHasErrors = submitted && fieldErrorCount > 0;
|
||||
|
||||
const classes = [
|
||||
@@ -153,6 +153,8 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
fieldHasErrors ? `${baseClass}--has-error` : `${baseClass}--has-no-error`,
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
if (!rows) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
id={`field-${path.replace(/\./gi, '__')}`}
|
||||
@@ -216,7 +218,6 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
<DraggableSortable
|
||||
ids={rows.map((row) => row.id)}
|
||||
onDragEnd={({ moveFromIndex, moveToIndex }) => moveRow(moveFromIndex, moveToIndex)}
|
||||
className={`${baseClass}__draggable-rows`}
|
||||
>
|
||||
{rows.length > 0 && rows.map((row, i) => (
|
||||
<DraggableSortableItem
|
||||
@@ -243,7 +244,6 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
rowIndex={i}
|
||||
indexPath={indexPath}
|
||||
labels={labels}
|
||||
hasMaxRows={hasMaxRows}
|
||||
/>
|
||||
)}
|
||||
</DraggableSortableItem>
|
||||
|
||||
@@ -28,7 +28,6 @@ type BlockFieldProps = UseDraggableSortableReturn & Pick<Props, 'path' | 'labels
|
||||
readOnly: boolean
|
||||
rowCount: number
|
||||
blockToRender: Block
|
||||
hasMaxRows?: boolean
|
||||
}
|
||||
export const BlockRow: React.FC<BlockFieldProps> = ({
|
||||
path: parentPath,
|
||||
@@ -51,7 +50,6 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
|
||||
permissions,
|
||||
blocks,
|
||||
blockToRender,
|
||||
hasMaxRows,
|
||||
}) => {
|
||||
const path = `${parentPath}.${rowIndex}`;
|
||||
const { i18n } = useTranslation();
|
||||
@@ -119,7 +117,6 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
|
||||
blockType={row.blockType}
|
||||
blocks={blocks}
|
||||
labels={labels}
|
||||
hasMaxRows={hasMaxRows}
|
||||
/>
|
||||
) : undefined}
|
||||
>
|
||||
|
||||
@@ -15,7 +15,6 @@ export const RowActions: React.FC<{
|
||||
rowIndex: number
|
||||
rowCount: number
|
||||
blockType: string
|
||||
hasMaxRows?: boolean
|
||||
}> = (props) => {
|
||||
const {
|
||||
addRow,
|
||||
@@ -27,7 +26,6 @@ export const RowActions: React.FC<{
|
||||
rowIndex,
|
||||
rowCount,
|
||||
blockType,
|
||||
hasMaxRows,
|
||||
} = props;
|
||||
|
||||
const { openModal, closeModal } = useModal();
|
||||
@@ -56,7 +54,6 @@ export const RowActions: React.FC<{
|
||||
moveRow={moveRow}
|
||||
removeRow={removeRow}
|
||||
index={rowIndex}
|
||||
hasMaxRows={hasMaxRows}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
@@ -80,7 +80,6 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
|
||||
return true;
|
||||
})();
|
||||
|
||||
const memoizedValidate = useCallback((value, options) => {
|
||||
// alternative locales can be null
|
||||
if (!editingDefaultLocale && value === null) {
|
||||
@@ -89,11 +88,12 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
return validate(value, { ...options, minRows, maxRows, required });
|
||||
}, [maxRows, minRows, required, validate, editingDefaultLocale]);
|
||||
|
||||
|
||||
const {
|
||||
showError,
|
||||
errorMessage,
|
||||
value,
|
||||
rows = [],
|
||||
rows,
|
||||
valid,
|
||||
} = useField<number>({
|
||||
path,
|
||||
@@ -141,7 +141,7 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
dispatchFields({ type: 'SET_ROW_COLLAPSED', path, collapsed, rowID, setDocFieldPreferences });
|
||||
}, [dispatchFields, path, setDocFieldPreferences]);
|
||||
|
||||
const hasMaxRows = maxRows && rows.length >= maxRows;
|
||||
const hasMaxRows = maxRows && rows?.length >= maxRows;
|
||||
|
||||
const fieldErrorCount = rows.reduce((total, row) => total + (row?.childErrorPaths?.size || 0), 0);
|
||||
const fieldHasErrors = submitted && fieldErrorCount + (valid ? 0 : 1) > 0;
|
||||
@@ -153,6 +153,8 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
fieldHasErrors ? `${baseClass}--has-error` : `${baseClass}--has-no-error`,
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
if (!rows) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
id={`field-${path.replace(/\./gi, '__')}`}
|
||||
@@ -245,7 +247,6 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
rowCount={rows.length}
|
||||
labels={labels}
|
||||
path={path}
|
||||
hasMaxRows={hasMaxRows}
|
||||
/>
|
||||
)}
|
||||
</DraggableSortableItem>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuth } from '../../utilities/Auth';
|
||||
import { useFormProcessing, useFormSubmitted, useForm, useFormFields } from '../Form/context';
|
||||
import { useFormProcessing, useFormSubmitted, useFormModified, useForm, useFormFields } from '../Form/context';
|
||||
import { Options, FieldType } from './types';
|
||||
import { useDocumentInfo } from '../../utilities/DocumentInfo';
|
||||
import { useOperation } from '../../utilities/OperationProvider';
|
||||
import useThrottledEffect from '../../../hooks/useThrottledEffect';
|
||||
import type { UPDATE } from '../Form/types';
|
||||
import { UPDATE } from '../Form/types';
|
||||
|
||||
/**
|
||||
* Get and set the value of a form field.
|
||||
@@ -24,6 +24,7 @@ const useField = <T, >(options: Options): FieldType<T> => {
|
||||
|
||||
const submitted = useFormSubmitted();
|
||||
const processing = useFormProcessing();
|
||||
const modified = useFormModified();
|
||||
const { user } = useAuth();
|
||||
const { id } = useDocumentInfo();
|
||||
const operation = useOperation();
|
||||
@@ -43,7 +44,7 @@ const useField = <T, >(options: Options): FieldType<T> => {
|
||||
const setValue = useCallback((e, disableModifyingForm = false) => {
|
||||
const val = (e && e.target) ? e.target.value : e;
|
||||
|
||||
if (!disableModifyingForm) {
|
||||
if (!modified && !disableModifyingForm) {
|
||||
if (typeof setModified === 'function') {
|
||||
// Update modified state after field value comes back
|
||||
// to avoid cursor jump caused by state value / DOM mismatch
|
||||
@@ -61,6 +62,7 @@ const useField = <T, >(options: Options): FieldType<T> => {
|
||||
});
|
||||
}, [
|
||||
setModified,
|
||||
modified,
|
||||
path,
|
||||
dispatchField,
|
||||
disableFormData,
|
||||
|
||||
@@ -22,23 +22,21 @@ const useThumbnail = (collection: SanitizedCollectionConfig, doc: Record<string,
|
||||
|
||||
const { serverURL } = useConfig();
|
||||
|
||||
if (typeof adminThumbnail === 'function') {
|
||||
const thumbnailURL = adminThumbnail({ doc });
|
||||
|
||||
if (!thumbnailURL) return false;
|
||||
|
||||
if (absoluteURLPattern.test(thumbnailURL) || base64Pattern.test(thumbnailURL)) {
|
||||
return thumbnailURL;
|
||||
}
|
||||
|
||||
return `${serverURL}${thumbnailURL}`;
|
||||
}
|
||||
|
||||
if (isImage(mimeType as string)) {
|
||||
if (typeof adminThumbnail === 'undefined' && url) {
|
||||
return url as string;
|
||||
}
|
||||
|
||||
if (typeof adminThumbnail === 'function') {
|
||||
const thumbnailURL = adminThumbnail({ doc });
|
||||
|
||||
if (absoluteURLPattern.test(thumbnailURL) || base64Pattern.test(thumbnailURL)) {
|
||||
return thumbnailURL;
|
||||
}
|
||||
|
||||
return `${serverURL}${thumbnailURL}`;
|
||||
}
|
||||
|
||||
if (sizes?.[adminThumbnail]?.url) {
|
||||
return sizes[adminThumbnail].url;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ async function forgotPassword(incomingArgs: Arguments): Promise<string | null> {
|
||||
args = (await hook({
|
||||
args,
|
||||
operation: 'forgotPassword',
|
||||
context: args.req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -123,7 +122,7 @@ async function forgotPassword(incomingArgs: Arguments): Promise<string | null> {
|
||||
|
||||
await collectionConfig.hooks.afterForgotPassword.reduce(async (priorHook, hook) => {
|
||||
await priorHook;
|
||||
await hook({ args, context: req.context });
|
||||
await hook({ args });
|
||||
}, Promise.resolve());
|
||||
|
||||
return token;
|
||||
|
||||
@@ -5,7 +5,6 @@ import { Payload } from '../../../payload';
|
||||
import { getDataLoader } from '../../../collections/dataloader';
|
||||
import i18n from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
collection: T
|
||||
@@ -28,7 +27,6 @@ async function localForgotPassword<T extends keyof GeneratedTypes['collections']
|
||||
disableEmail,
|
||||
req = {} as PayloadRequest,
|
||||
} = options;
|
||||
setRequestContext(options.req);
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import { Payload } from '../../../payload';
|
||||
import { getDataLoader } from '../../../collections/dataloader';
|
||||
import i18n from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
||||
collection: TSlug
|
||||
@@ -38,8 +37,6 @@ async function localLogin<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
overrideAccess = true,
|
||||
showHiddenFields,
|
||||
} = options;
|
||||
setRequestContext(options.req);
|
||||
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import { PayloadRequest } from '../../../express/types';
|
||||
import { getDataLoader } from '../../../collections/dataloader';
|
||||
import i18n from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
collection: T
|
||||
@@ -27,7 +26,6 @@ async function localResetPassword<T extends keyof GeneratedTypes['collections']>
|
||||
overrideAccess,
|
||||
req = {} as PayloadRequest,
|
||||
} = options;
|
||||
setRequestContext(options.req);
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import unlock from '../unlock';
|
||||
import { getDataLoader } from '../../../collections/dataloader';
|
||||
import i18n from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
collection: T
|
||||
@@ -26,7 +25,6 @@ async function localUnlock<T extends keyof GeneratedTypes['collections']>(
|
||||
overrideAccess = true,
|
||||
req = {} as PayloadRequest,
|
||||
} = options;
|
||||
setRequestContext(options.req);
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
args = (await hook({
|
||||
args,
|
||||
operation: 'login',
|
||||
context: args.req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -134,7 +133,6 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
user = (await hook({
|
||||
user,
|
||||
req: args.req,
|
||||
context: req.context,
|
||||
})) || user;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -174,7 +172,6 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
user,
|
||||
req: args.req,
|
||||
token,
|
||||
context: req.context,
|
||||
}) || user;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -189,7 +186,6 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -202,7 +198,6 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
user = await hook({
|
||||
req,
|
||||
doc: user,
|
||||
context: req.context,
|
||||
}) || user;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ async function logout(incomingArgs: Arguments): Promise<string> {
|
||||
args = (await hook({
|
||||
req,
|
||||
res,
|
||||
context: req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ async function me({
|
||||
response = await hook({
|
||||
req,
|
||||
response,
|
||||
context: req.context,
|
||||
}) || response;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ async function refresh(incomingArgs: Arguments): Promise<Result> {
|
||||
args = (await hook({
|
||||
args,
|
||||
operation: 'refresh',
|
||||
context: args.req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -115,7 +114,6 @@ async function refresh(incomingArgs: Arguments): Promise<Result> {
|
||||
res: args.res,
|
||||
exp,
|
||||
token: refreshedToken,
|
||||
context: args.req.context,
|
||||
})) || response;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -19,12 +19,12 @@ export const getDevConfig = (payloadConfig: SanitizedConfig): Configuration => {
|
||||
entry: {
|
||||
...baseConfig.entry,
|
||||
main: [
|
||||
`webpack-hot-middleware/client?path=${payloadConfig.routes.admin}/__webpack_hmr`,
|
||||
require.resolve('webpack-hot-middleware/client'),
|
||||
...(baseConfig.entry.main as string[]),
|
||||
],
|
||||
},
|
||||
output: {
|
||||
publicPath: `${payloadConfig.routes.admin}/`,
|
||||
publicPath: payloadConfig.routes.admin,
|
||||
path: '/',
|
||||
filename: '[name].js',
|
||||
},
|
||||
|
||||
@@ -11,14 +11,14 @@ const router = express.Router();
|
||||
|
||||
type DevAdminType = (options: { payload: Payload }) => Promise<PayloadHandler>;
|
||||
export const devAdmin: DevAdminType = async ({ payload }) => {
|
||||
router.use(history());
|
||||
payload.express.use(payload.config.routes.admin, history());
|
||||
|
||||
try {
|
||||
const webpackConfig = getDevConfig(payload.config);
|
||||
const compiler = webpack(webpackConfig);
|
||||
|
||||
router.use(webpackDevMiddleware(compiler, {
|
||||
publicPath: '/',
|
||||
publicPath: webpackConfig.output.publicPath as string,
|
||||
}));
|
||||
|
||||
router.use(webpackHotMiddleware(compiler));
|
||||
|
||||
@@ -10,7 +10,7 @@ import getBaseUploadFields from '../../uploads/getBaseFields';
|
||||
import { formatLabels } from '../../utilities/formatLabels';
|
||||
import { authDefaults, defaults } from './defaults';
|
||||
import { Config } from '../../config/types';
|
||||
import baseVersionFields from '../../versions/baseFields';
|
||||
import getBaseVersionFields from '../../versions/baseFields';
|
||||
import TimestampsRequired from '../../errors/TimestampsRequired';
|
||||
import mergeBaseFields from '../../fields/mergeBaseFields';
|
||||
import { extractTranslations } from '../../translations/extractTranslations';
|
||||
@@ -87,7 +87,7 @@ const sanitizeCollection = (config: Config, collection: CollectionConfig): Sanit
|
||||
};
|
||||
}
|
||||
|
||||
sanitized.fields = mergeBaseFields(sanitized.fields, baseVersionFields);
|
||||
sanitized.fields = mergeBaseFields(sanitized.fields, getBaseVersionFields(config));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Response } from 'express';
|
||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||
import { Access, Endpoint, EntityDescription, GeneratePreviewURL } from '../../config/types';
|
||||
import { Field } from '../../fields/config/types';
|
||||
import { PayloadRequest, RequestContext } from '../../express/types';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
import { Auth, IncomingAuthType, User } from '../../auth/types';
|
||||
import { IncomingUploadType, Upload } from '../../uploads/types';
|
||||
import { IncomingCollectionVersions, SanitizedCollectionVersions } from '../../versions/types';
|
||||
@@ -49,7 +49,6 @@ export type BeforeOperationHook = (args: {
|
||||
* Hook operation being performed
|
||||
*/
|
||||
operation: HookOperationType;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type BeforeValidateHook<T extends TypeWithID = any> = (args: {
|
||||
@@ -65,7 +64,6 @@ export type BeforeValidateHook<T extends TypeWithID = any> = (args: {
|
||||
* `undefined` on 'create' operation
|
||||
*/
|
||||
originalDoc?: T;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type BeforeChangeHook<T extends TypeWithID = any> = (args: {
|
||||
@@ -81,7 +79,6 @@ export type BeforeChangeHook<T extends TypeWithID = any> = (args: {
|
||||
* `undefined` on 'create' operation
|
||||
*/
|
||||
originalDoc?: T;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type AfterChangeHook<T extends TypeWithID = any> = (args: {
|
||||
@@ -92,62 +89,53 @@ export type AfterChangeHook<T extends TypeWithID = any> = (args: {
|
||||
* Hook operation being performed
|
||||
*/
|
||||
operation: CreateOrUpdateOperation;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type BeforeReadHook<T extends TypeWithID = any> = (args: {
|
||||
doc: T;
|
||||
req: PayloadRequest;
|
||||
query: { [key: string]: any };
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type AfterReadHook<T extends TypeWithID = any> = (args: {
|
||||
doc: T;
|
||||
req: PayloadRequest;
|
||||
query?: { [key: string]: any };
|
||||
findMany?: boolean;
|
||||
context: RequestContext;
|
||||
findMany?: boolean
|
||||
}) => any;
|
||||
|
||||
export type BeforeDeleteHook = (args: {
|
||||
req: PayloadRequest;
|
||||
id: string | number;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type AfterDeleteHook<T extends TypeWithID = any> = (args: {
|
||||
doc: T;
|
||||
req: PayloadRequest;
|
||||
id: string | number;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type AfterErrorHook = (err: Error, res: unknown, context: RequestContext) => { response: any, status: number } | void;
|
||||
export type AfterErrorHook = (err: Error, res: unknown) => { response: any, status: number } | void;
|
||||
|
||||
export type BeforeLoginHook<T extends TypeWithID = any> = (args: {
|
||||
req: PayloadRequest;
|
||||
user: T;
|
||||
context: RequestContext;
|
||||
user: T
|
||||
}) => any;
|
||||
|
||||
export type AfterLoginHook<T extends TypeWithID = any> = (args: {
|
||||
req: PayloadRequest;
|
||||
user: T;
|
||||
token: string;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type AfterLogoutHook<T extends TypeWithID = any> = (args: {
|
||||
req: PayloadRequest;
|
||||
res: Response;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type AfterMeHook<T extends TypeWithID = any> = (args: {
|
||||
req: PayloadRequest;
|
||||
response: unknown;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type AfterRefreshHook<T extends TypeWithID = any> = (args: {
|
||||
@@ -155,12 +143,10 @@ export type AfterRefreshHook<T extends TypeWithID = any> = (args: {
|
||||
res: Response;
|
||||
token: string;
|
||||
exp: number;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
export type AfterForgotPasswordHook = (args: {
|
||||
args?: any;
|
||||
context: RequestContext;
|
||||
}) => any;
|
||||
|
||||
type BeforeDuplicateArgs<T> = {
|
||||
@@ -276,7 +262,7 @@ export type CollectionConfig = {
|
||||
graphQL?: {
|
||||
singularName?: string
|
||||
pluralName?: string
|
||||
} | false
|
||||
}
|
||||
/**
|
||||
* Options used in typescript generation
|
||||
*/
|
||||
|
||||
@@ -41,9 +41,6 @@ function initCollectionsGraphQL(payload: Payload): void {
|
||||
versions,
|
||||
},
|
||||
} = collection;
|
||||
|
||||
if (!graphQL) return;
|
||||
|
||||
const { fields } = config;
|
||||
|
||||
let singularName;
|
||||
|
||||
@@ -54,7 +54,6 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
args = (await hook({
|
||||
args,
|
||||
operation: 'create',
|
||||
context: args.req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -131,7 +130,6 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
operation: 'create',
|
||||
overrideAccess,
|
||||
req,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -145,7 +143,6 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
data,
|
||||
req,
|
||||
operation: 'create',
|
||||
context: req.context,
|
||||
})) || data;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -168,7 +165,6 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
data,
|
||||
req,
|
||||
operation: 'create',
|
||||
context: req.context,
|
||||
})) || data;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -184,7 +180,6 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
operation: 'create',
|
||||
req,
|
||||
skipValidation: shouldSaveDraft,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -208,7 +203,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
doc: resultWithLocales,
|
||||
payload: req.payload,
|
||||
password: data.password as string,
|
||||
});
|
||||
})
|
||||
} else {
|
||||
try {
|
||||
doc = await Model.create(resultWithLocales);
|
||||
@@ -271,7 +266,6 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -284,7 +278,6 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
result = await hook({
|
||||
req,
|
||||
doc: result,
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -299,7 +292,6 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
entityConfig: collectionConfig,
|
||||
operation: 'create',
|
||||
req,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -314,7 +306,6 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
previousDoc: {},
|
||||
req: args.req,
|
||||
operation: 'create',
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
args = (await hook({
|
||||
args,
|
||||
operation: 'delete',
|
||||
context: args.req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -117,7 +116,6 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
return hook({
|
||||
req,
|
||||
id,
|
||||
context: req.context,
|
||||
});
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -152,7 +150,6 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -165,7 +162,6 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
result = await hook({
|
||||
req,
|
||||
doc: result || doc,
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -180,7 +176,6 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
req,
|
||||
id,
|
||||
doc: result,
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
||||
args = (await hook({
|
||||
args,
|
||||
operation: 'delete',
|
||||
context: args.req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -73,7 +72,6 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
||||
return hook({
|
||||
req,
|
||||
id,
|
||||
context: req.context,
|
||||
});
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -147,7 +145,6 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -160,7 +157,6 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
||||
result = await hook({
|
||||
req,
|
||||
doc: result,
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -171,7 +167,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(inc
|
||||
await collectionConfig.hooks.afterDelete.reduce(async (priorHook, hook) => {
|
||||
await priorHook;
|
||||
|
||||
result = await hook({ req, id, doc: result, context: req.context }) || result;
|
||||
result = await hook({ req, id, doc: result }) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
// /////////////////////////////////////
|
||||
|
||||
@@ -41,7 +41,6 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
||||
args = (await hook({
|
||||
args,
|
||||
operation: 'read',
|
||||
context: args.req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -181,7 +180,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
||||
await collectionConfig.hooks.beforeRead.reduce(async (priorHook, hook) => {
|
||||
await priorHook;
|
||||
|
||||
docRef = await hook({ req, query, doc: docRef, context: req.context }) || docRef;
|
||||
docRef = await hook({ req, query, doc: docRef }) || docRef;
|
||||
}, Promise.resolve());
|
||||
|
||||
return docRef;
|
||||
@@ -203,7 +202,6 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
||||
req,
|
||||
showHiddenFields,
|
||||
findMany: true,
|
||||
context: req.context,
|
||||
}))),
|
||||
};
|
||||
|
||||
@@ -219,7 +217,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
||||
await collectionConfig.hooks.afterRead.reduce(async (priorHook, hook) => {
|
||||
await priorHook;
|
||||
|
||||
docRef = await hook({ req, query, doc: docRef, findMany: true, context: req.context }) || doc;
|
||||
docRef = await hook({ req, query, doc: docRef, findMany: true }) || doc;
|
||||
}, Promise.resolve());
|
||||
|
||||
return docRef;
|
||||
|
||||
@@ -35,7 +35,6 @@ async function findByID<T extends TypeWithID>(
|
||||
args = (await hook({
|
||||
args,
|
||||
operation: 'read',
|
||||
context: args.req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -139,7 +138,6 @@ async function findByID<T extends TypeWithID>(
|
||||
req,
|
||||
query,
|
||||
doc: result,
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -155,7 +153,6 @@ async function findByID<T extends TypeWithID>(
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -169,7 +166,6 @@ async function findByID<T extends TypeWithID>(
|
||||
req,
|
||||
query,
|
||||
doc: result,
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -98,7 +98,6 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
req,
|
||||
query,
|
||||
doc: result.version,
|
||||
context: req.context,
|
||||
}) || result.version;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -114,7 +113,6 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -128,7 +126,6 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
req,
|
||||
query,
|
||||
doc: result.version,
|
||||
context: req.context,
|
||||
}) || result.version;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
||||
await collectionConfig.hooks.beforeRead.reduce(async (priorHook, hook) => {
|
||||
await priorHook;
|
||||
|
||||
docRef.version = await hook({ req, query, doc: docRef.version, context: req.context }) || docRef.version;
|
||||
docRef.version = await hook({ req, query, doc: docRef.version }) || docRef.version;
|
||||
}, Promise.resolve());
|
||||
|
||||
return docRef;
|
||||
@@ -133,7 +133,6 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
||||
req,
|
||||
showHiddenFields,
|
||||
findMany: true,
|
||||
context: req.context,
|
||||
}),
|
||||
}))),
|
||||
};
|
||||
@@ -150,7 +149,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
||||
await collectionConfig.hooks.afterRead.reduce(async (priorHook, hook) => {
|
||||
await priorHook;
|
||||
|
||||
docRef.version = await hook({ req, query, doc: doc.version, findMany: true, context: req.context }) || doc.version;
|
||||
docRef.version = await hook({ req, query, doc: doc.version, findMany: true }) || doc.version;
|
||||
}, Promise.resolve());
|
||||
|
||||
return docRef;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||
import { UploadedFile } from 'express-fileupload';
|
||||
import { MarkOptional } from 'ts-essentials';
|
||||
import { Payload } from '../../../payload';
|
||||
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||
import { PayloadRequest } from '../../../express/types';
|
||||
import { Document } from '../../../types';
|
||||
import getFileByPath from '../../../uploads/getFileByPath';
|
||||
import create from '../create';
|
||||
@@ -10,7 +10,6 @@ import { getDataLoader } from '../../dataloader';
|
||||
import { File } from '../../../uploads/types';
|
||||
import i18n from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
||||
collection: TSlug
|
||||
@@ -27,10 +26,6 @@ export type Options<TSlug extends keyof GeneratedTypes['collections']> = {
|
||||
overwriteExistingFiles?: boolean
|
||||
req?: PayloadRequest
|
||||
draft?: boolean
|
||||
/**
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
}
|
||||
|
||||
export default async function createLocal<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
@@ -52,9 +47,7 @@ export default async function createLocal<TSlug extends keyof GeneratedTypes['co
|
||||
overwriteExistingFiles = false,
|
||||
req = {} as PayloadRequest,
|
||||
draft,
|
||||
context,
|
||||
} = options;
|
||||
setRequestContext(req, context);
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Config as GeneratedTypes } from '../../../generated-types';
|
||||
import { Document, Where } from '../../../types';
|
||||
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||
import { PayloadRequest } from '../../../express/types';
|
||||
import { Payload } from '../../../payload';
|
||||
import deleteOperation from '../delete';
|
||||
import deleteByID from '../deleteByID';
|
||||
@@ -8,10 +8,8 @@ import { getDataLoader } from '../../dataloader';
|
||||
import i18n from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { BulkOperationResult } from '../../config/types';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type BaseOptions<T extends keyof GeneratedTypes['collections']> = {
|
||||
req?: PayloadRequest,
|
||||
collection: T
|
||||
depth?: number
|
||||
locale?: string
|
||||
@@ -19,10 +17,6 @@ export type BaseOptions<T extends keyof GeneratedTypes['collections']> = {
|
||||
user?: Document
|
||||
overrideAccess?: boolean
|
||||
showHiddenFields?: boolean
|
||||
/**
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
}
|
||||
|
||||
export type ByIDOptions<T extends keyof GeneratedTypes['collections']> = BaseOptions<T> & {
|
||||
@@ -51,7 +45,6 @@ async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>(pa
|
||||
user,
|
||||
overrideAccess = true,
|
||||
showHiddenFields,
|
||||
context,
|
||||
} = options;
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
@@ -70,7 +63,6 @@ async function deleteLocal<TSlug extends keyof GeneratedTypes['collections']>(pa
|
||||
payload,
|
||||
i18n: i18n(payload.config.i18n),
|
||||
} as PayloadRequest;
|
||||
setRequestContext(req, context);
|
||||
|
||||
if (!req.t) req.t = req.i18n.t;
|
||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||
|
||||
@@ -2,12 +2,11 @@ import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||
import { PaginatedDocs } from '../../../mongoose/types';
|
||||
import { Document, Where } from '../../../types';
|
||||
import { Payload } from '../../../payload';
|
||||
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||
import { PayloadRequest } from '../../../express/types';
|
||||
import find from '../find';
|
||||
import { getDataLoader } from '../../dataloader';
|
||||
import i18n from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
collection: T
|
||||
@@ -26,10 +25,6 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
where?: Where
|
||||
draft?: boolean
|
||||
req?: PayloadRequest
|
||||
/**
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
}
|
||||
|
||||
export default async function findLocal<T extends keyof GeneratedTypes['collections']>(
|
||||
@@ -53,9 +48,7 @@ export default async function findLocal<T extends keyof GeneratedTypes['collecti
|
||||
draft = false,
|
||||
pagination = true,
|
||||
req = {} as PayloadRequest,
|
||||
context,
|
||||
} = options;
|
||||
setRequestContext(options.req, context);
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||
import { PayloadRequest } from '../../../express/types';
|
||||
import { Document } from '../../../types';
|
||||
import findByID from '../findByID';
|
||||
import { Payload } from '../../../payload';
|
||||
import { getDataLoader } from '../../dataloader';
|
||||
import i18n from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
collection: T
|
||||
@@ -21,10 +20,6 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
disableErrors?: boolean
|
||||
req?: PayloadRequest
|
||||
draft?: boolean
|
||||
/**
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext,
|
||||
}
|
||||
|
||||
export default async function findByIDLocal<T extends keyof GeneratedTypes['collections']>(
|
||||
@@ -44,9 +39,7 @@ export default async function findByIDLocal<T extends keyof GeneratedTypes['coll
|
||||
showHiddenFields,
|
||||
req = {} as PayloadRequest,
|
||||
draft = false,
|
||||
context,
|
||||
} = options;
|
||||
setRequestContext(options.req, context);
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||
import { Payload } from '../../../payload';
|
||||
import { Document } from '../../../types';
|
||||
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||
import { PayloadRequest } from '../../../express/types';
|
||||
import { TypeWithVersion } from '../../../versions/types';
|
||||
import findVersionByID from '../findVersionByID';
|
||||
import { getDataLoader } from '../../dataloader';
|
||||
import i18n from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
collection: T
|
||||
@@ -20,11 +19,6 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
showHiddenFields?: boolean
|
||||
disableErrors?: boolean
|
||||
req?: PayloadRequest
|
||||
draft?: boolean
|
||||
/**
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext,
|
||||
}
|
||||
|
||||
export default async function findVersionByIDLocal<T extends keyof GeneratedTypes['collections']>(
|
||||
@@ -41,9 +35,7 @@ export default async function findVersionByIDLocal<T extends keyof GeneratedType
|
||||
disableErrors = false,
|
||||
showHiddenFields,
|
||||
req = {} as PayloadRequest,
|
||||
context,
|
||||
} = options;
|
||||
setRequestContext(options.req, context);
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null;
|
||||
|
||||
@@ -3,12 +3,11 @@ import { Payload } from '../../../payload';
|
||||
import { Document, Where } from '../../../types';
|
||||
import { PaginatedDocs } from '../../../mongoose/types';
|
||||
import { TypeWithVersion } from '../../../versions/types';
|
||||
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||
import { PayloadRequest } from '../../../express/types';
|
||||
import findVersions from '../findVersions';
|
||||
import { getDataLoader } from '../../dataloader';
|
||||
import i18nInit from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
collection: T
|
||||
@@ -22,11 +21,6 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
showHiddenFields?: boolean
|
||||
sort?: string
|
||||
where?: Where
|
||||
draft?: boolean
|
||||
/**
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext,
|
||||
}
|
||||
|
||||
export default async function findVersionsLocal<T extends keyof GeneratedTypes['collections']>(
|
||||
@@ -45,7 +39,6 @@ export default async function findVersionsLocal<T extends keyof GeneratedTypes['
|
||||
overrideAccess = true,
|
||||
showHiddenFields,
|
||||
sort,
|
||||
context,
|
||||
} = options;
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
@@ -64,7 +57,6 @@ export default async function findVersionsLocal<T extends keyof GeneratedTypes['
|
||||
payload,
|
||||
i18n,
|
||||
} as PayloadRequest;
|
||||
setRequestContext(req, context);
|
||||
|
||||
if (!req.t) req.t = req.i18n.t;
|
||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Config as GeneratedTypes } from 'payload/generated-types';
|
||||
import { Payload } from '../../../payload';
|
||||
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||
import { PayloadRequest } from '../../../express/types';
|
||||
import { Document } from '../../../types';
|
||||
import { getDataLoader } from '../../dataloader';
|
||||
import restoreVersion from '../restoreVersion';
|
||||
import i18nInit from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
collection: T
|
||||
@@ -17,11 +16,6 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
|
||||
user?: Document
|
||||
overrideAccess?: boolean
|
||||
showHiddenFields?: boolean
|
||||
draft?: boolean
|
||||
/**
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext,
|
||||
}
|
||||
|
||||
export default async function restoreVersionLocal<T extends keyof GeneratedTypes['collections']>(
|
||||
@@ -37,7 +31,6 @@ export default async function restoreVersionLocal<T extends keyof GeneratedTypes
|
||||
user,
|
||||
overrideAccess = true,
|
||||
showHiddenFields,
|
||||
context,
|
||||
} = options;
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
@@ -56,7 +49,6 @@ export default async function restoreVersionLocal<T extends keyof GeneratedTypes
|
||||
i18n,
|
||||
t: i18n.t,
|
||||
} as PayloadRequest;
|
||||
setRequestContext(req, context);
|
||||
|
||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||
|
||||
|
||||
@@ -4,14 +4,13 @@ import { Payload } from '../../../payload';
|
||||
import { Document, Where } from '../../../types';
|
||||
import getFileByPath from '../../../uploads/getFileByPath';
|
||||
import update from '../update';
|
||||
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||
import { PayloadRequest } from '../../../express/types';
|
||||
import { getDataLoader } from '../../dataloader';
|
||||
import { File } from '../../../uploads/types';
|
||||
import i18nInit from '../../../translations/init';
|
||||
import { APIError } from '../../../errors';
|
||||
import updateByID from '../updateByID';
|
||||
import { BulkOperationResult } from '../../config/types';
|
||||
import { setRequestContext } from '../../../express/setRequestContext';
|
||||
|
||||
export type BaseOptions<TSlug extends keyof GeneratedTypes['collections']> = {
|
||||
collection: TSlug
|
||||
@@ -27,10 +26,6 @@ export type BaseOptions<TSlug extends keyof GeneratedTypes['collections']> = {
|
||||
overwriteExistingFiles?: boolean
|
||||
draft?: boolean
|
||||
autosave?: boolean
|
||||
/**
|
||||
* context, which will then be passed to req.context, which can be read by hooks
|
||||
*/
|
||||
context?: RequestContext
|
||||
}
|
||||
|
||||
export type ByIDOptions<TSlug extends keyof GeneratedTypes['collections']> = BaseOptions<TSlug> & {
|
||||
@@ -65,7 +60,6 @@ async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>(pa
|
||||
autosave,
|
||||
id,
|
||||
where,
|
||||
context,
|
||||
} = options;
|
||||
|
||||
const collection = payload.collections[collectionSlug];
|
||||
@@ -88,7 +82,6 @@ async function updateLocal<TSlug extends keyof GeneratedTypes['collections']>(pa
|
||||
file: file ?? await getFileByPath(filePath),
|
||||
},
|
||||
} as PayloadRequest;
|
||||
setRequestContext(req, context);
|
||||
|
||||
if (!req.t) req.t = req.i18n.t;
|
||||
if (!req.payloadDataLoader) req.payloadDataLoader = getDataLoader(req);
|
||||
|
||||
@@ -143,7 +143,6 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
req,
|
||||
overrideAccess,
|
||||
showHiddenFields,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -156,7 +155,6 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
result = await hook({
|
||||
req,
|
||||
doc: result,
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -170,7 +168,6 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
previousDoc: prevDocWithLocales,
|
||||
entityConfig: collectionConfig,
|
||||
operation: 'update',
|
||||
context: req.context,
|
||||
req,
|
||||
});
|
||||
|
||||
@@ -186,7 +183,6 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
req,
|
||||
previousDoc: prevDocWithLocales,
|
||||
operation: 'update',
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
args = (await hook({
|
||||
args,
|
||||
operation: 'update',
|
||||
context: args.req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -150,7 +149,6 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
req,
|
||||
overrideAccess: true,
|
||||
showHiddenFields: true,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
await deleteAssociatedFiles({ config, collectionConfig, files: filesToUpload, doc: docWithLocales, t, overrideDelete: false });
|
||||
@@ -167,7 +165,6 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
operation: 'update',
|
||||
overrideAccess,
|
||||
req,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -182,7 +179,6 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
req,
|
||||
operation: 'update',
|
||||
originalDoc,
|
||||
context: req.context,
|
||||
})) || data;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -206,7 +202,6 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
req,
|
||||
originalDoc,
|
||||
operation: 'update',
|
||||
context: req.context,
|
||||
})) || data;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -223,7 +218,6 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
operation: 'update',
|
||||
req,
|
||||
skipValidation: shouldSaveDraft || data._status === 'draft',
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -281,7 +275,6 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
req,
|
||||
overrideAccess,
|
||||
showHiddenFields,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -294,7 +287,6 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
result = await hook({
|
||||
req,
|
||||
doc: result,
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -309,7 +301,6 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
entityConfig: collectionConfig,
|
||||
operation: 'update',
|
||||
req,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -324,7 +315,6 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
previousDoc: originalDoc,
|
||||
req,
|
||||
operation: 'update',
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
args = (await hook({
|
||||
args,
|
||||
operation: 'update',
|
||||
context: args.req.context,
|
||||
})) || args;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -131,7 +130,6 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
req,
|
||||
overrideAccess: true,
|
||||
showHiddenFields: true,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -167,7 +165,6 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
operation: 'update',
|
||||
overrideAccess,
|
||||
req,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -182,7 +179,6 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
req,
|
||||
operation: 'update',
|
||||
originalDoc,
|
||||
context: req.context,
|
||||
})) || data;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -206,7 +202,6 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
req,
|
||||
originalDoc,
|
||||
operation: 'update',
|
||||
context: req.context,
|
||||
})) || data;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -223,19 +218,18 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
operation: 'update',
|
||||
req,
|
||||
skipValidation: shouldSaveDraft || data._status === 'draft',
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
// Handle potential password update
|
||||
// /////////////////////////////////////
|
||||
|
||||
const dataToUpdate: Record<string, unknown> = { ...result };
|
||||
const dataToUpdate: Record<string, unknown> = { ...result }
|
||||
|
||||
if (shouldSavePassword && typeof password === 'string') {
|
||||
const { hash, salt } = await generatePasswordSaltHash({ password });
|
||||
dataToUpdate.salt = salt;
|
||||
dataToUpdate.hash = hash;
|
||||
const { hash, salt } = await generatePasswordSaltHash({ password })
|
||||
dataToUpdate.salt = salt
|
||||
dataToUpdate.hash = hash
|
||||
delete data.password;
|
||||
delete result.password;
|
||||
}
|
||||
@@ -293,7 +287,6 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
req,
|
||||
overrideAccess,
|
||||
showHiddenFields,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -306,7 +299,6 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
result = await hook({
|
||||
req,
|
||||
doc: result,
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
@@ -321,7 +313,6 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
entityConfig: collectionConfig,
|
||||
operation: 'update',
|
||||
req,
|
||||
context: req.context,
|
||||
});
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -336,7 +327,6 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
previousDoc: originalDoc,
|
||||
req,
|
||||
operation: 'update',
|
||||
context: req.context,
|
||||
}) || result;
|
||||
}, Promise.resolve());
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ export const sanitizeConfig = (config: Config): SanitizedConfig => {
|
||||
checkDuplicateCollections(sanitizedConfig.collections);
|
||||
|
||||
if (sanitizedConfig.globals.length > 0) {
|
||||
sanitizedConfig.globals = sanitizeGlobals(sanitizedConfig.collections, sanitizedConfig.globals);
|
||||
sanitizedConfig.globals = sanitizeGlobals(config, sanitizedConfig.collections, sanitizedConfig.globals);
|
||||
}
|
||||
|
||||
if (typeof sanitizedConfig.serverURL === 'undefined') {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { hasWhereAccessResult } from '../auth';
|
||||
import { Where } from '../types';
|
||||
|
||||
export const combineQueries = (where: Where, access: Where | boolean): Where => {
|
||||
if (!where && !access) return {};
|
||||
|
||||
const result: Where = {
|
||||
and: [],
|
||||
};
|
||||
|
||||
if (where) result.and.push(where);
|
||||
if (hasWhereAccessResult(access)) result.and.push(access);
|
||||
|
||||
return result;
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { Configuration } from 'webpack';
|
||||
import { MarkOptional } from 'ts-essentials';
|
||||
import { transaction } from './transaction';
|
||||
import { migrate } from './migrations/migrate';
|
||||
import { migrateStatus } from './migrations/migrateStatus';
|
||||
import { migrateDown } from './migrations/migrateDown';
|
||||
import { migrateRefresh } from './migrations/migrateRefresh';
|
||||
import { migrateReset } from './migrations/migrateReset';
|
||||
import { DatabaseAdapter } from './types';
|
||||
import { createMigration } from './migrations/createMigration';
|
||||
|
||||
export function createDatabaseAdapter<T extends DatabaseAdapter>(args: MarkOptional<T,
|
||||
| 'transaction'
|
||||
| 'migrate'
|
||||
| 'createMigration'
|
||||
| 'migrateStatus'
|
||||
| 'migrateDown'
|
||||
| 'migrateRefresh'
|
||||
| 'migrateReset'
|
||||
| 'migrateFresh'
|
||||
| 'migrationDir'>): T {
|
||||
// Need to implement DB Webpack config extensions here
|
||||
if (args.webpack) {
|
||||
const existingWebpackConfig = args.payload.config.admin.webpack ? args.payload.config.admin.webpack : (webpackConfig) => webpackConfig;
|
||||
args.payload.config.admin.webpack = (webpackConfig: Configuration) => {
|
||||
return args.webpack(
|
||||
existingWebpackConfig(webpackConfig),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
transaction,
|
||||
migrate,
|
||||
createMigration,
|
||||
migrateStatus,
|
||||
migrateDown,
|
||||
migrateRefresh,
|
||||
migrateReset,
|
||||
migrateFresh: async () => null,
|
||||
...args,
|
||||
} as T;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { Where, WhereField } from '../types';
|
||||
|
||||
// Take a where query and flatten it to all top-level operators
|
||||
const flattenWhereToOperators = (query: Where): WhereField[] => Object.entries(query).reduce((flattenedConstraints, [key, val]) => {
|
||||
if ((key === 'and' || key === 'or') && Array.isArray(val)) {
|
||||
return [
|
||||
...flattenedConstraints,
|
||||
...val.reduce((subVals, subVal) => {
|
||||
return [
|
||||
...subVals,
|
||||
...flattenWhereToOperators(subVal),
|
||||
];
|
||||
}, []),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
...flattenedConstraints,
|
||||
val,
|
||||
];
|
||||
}, []);
|
||||
|
||||
export default flattenWhereToOperators;
|
||||
@@ -1,150 +0,0 @@
|
||||
import { Field, fieldAffectsData } from '../fields/config/types';
|
||||
import flattenFields from '../utilities/flattenTopLevelFields';
|
||||
import { PathToQuery } from './queryValidation/types';
|
||||
import { Payload } from '..';
|
||||
|
||||
export async function getLocalizedPaths({
|
||||
payload,
|
||||
locale,
|
||||
collectionSlug,
|
||||
globalSlug,
|
||||
fields,
|
||||
incomingPath,
|
||||
overrideAccess = false,
|
||||
}: {
|
||||
payload: Payload
|
||||
locale?: string
|
||||
collectionSlug?: string
|
||||
globalSlug?: string
|
||||
fields: Field[]
|
||||
incomingPath: string
|
||||
overrideAccess?: boolean,
|
||||
}): Promise<PathToQuery[]> {
|
||||
const pathSegments = incomingPath.split('.');
|
||||
const localizationConfig = payload.config.localization;
|
||||
|
||||
let paths: PathToQuery[] = [
|
||||
{
|
||||
path: '',
|
||||
complete: false,
|
||||
field: undefined,
|
||||
fields: flattenFields(fields, false),
|
||||
collectionSlug,
|
||||
globalSlug,
|
||||
invalid: false,
|
||||
},
|
||||
];
|
||||
|
||||
for (let i = 0; i < pathSegments.length; i += 1) {
|
||||
const segment = pathSegments[i];
|
||||
|
||||
const lastIncompletePath = paths.find(({ complete }) => !complete);
|
||||
|
||||
if (lastIncompletePath) {
|
||||
const { path } = lastIncompletePath;
|
||||
let currentPath = path ? `${path}.${segment}` : segment;
|
||||
|
||||
const matchedField = lastIncompletePath.fields.find((field) => fieldAffectsData(field) && field.name === segment);
|
||||
lastIncompletePath.field = matchedField;
|
||||
|
||||
if (currentPath === 'globalType' && globalSlug) {
|
||||
lastIncompletePath.path = currentPath;
|
||||
lastIncompletePath.complete = true;
|
||||
lastIncompletePath.field = {
|
||||
name: 'globalType',
|
||||
type: 'text',
|
||||
};
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
if (matchedField) {
|
||||
if ('hidden' in matchedField && matchedField.hidden && !overrideAccess) {
|
||||
lastIncompletePath.invalid = true;
|
||||
}
|
||||
|
||||
const nextSegment = pathSegments[i + 1];
|
||||
const nextSegmentIsLocale = localizationConfig && localizationConfig.locales.includes(nextSegment);
|
||||
|
||||
if (nextSegmentIsLocale) {
|
||||
// Skip the next iteration, because it's a locale
|
||||
i += 1;
|
||||
currentPath = `${currentPath}.${nextSegment}`;
|
||||
} else if (localizationConfig && 'localized' in matchedField && matchedField.localized) {
|
||||
currentPath = `${currentPath}.${locale}`;
|
||||
}
|
||||
|
||||
switch (matchedField.type) {
|
||||
case 'blocks':
|
||||
case 'richText':
|
||||
case 'json': {
|
||||
const upcomingSegments = pathSegments.slice(i + 1).join('.');
|
||||
lastIncompletePath.complete = true;
|
||||
lastIncompletePath.path = upcomingSegments ? `${currentPath}.${upcomingSegments}` : currentPath;
|
||||
return paths;
|
||||
}
|
||||
|
||||
case 'relationship':
|
||||
case 'upload': {
|
||||
// If this is a polymorphic relation,
|
||||
// We only support querying directly (no nested querying)
|
||||
if (typeof matchedField.relationTo !== 'string') {
|
||||
const lastSegmentIsValid = ['value', 'relationTo'].includes(pathSegments[pathSegments.length - 1]);
|
||||
|
||||
if (lastSegmentIsValid) {
|
||||
lastIncompletePath.complete = true;
|
||||
lastIncompletePath.path = pathSegments.join('.');
|
||||
} else {
|
||||
lastIncompletePath.invalid = true;
|
||||
return paths;
|
||||
}
|
||||
} else {
|
||||
lastIncompletePath.complete = true;
|
||||
lastIncompletePath.path = currentPath;
|
||||
|
||||
const nestedPathToQuery = pathSegments.slice(nextSegmentIsLocale ? i + 2 : i + 1).join('.');
|
||||
|
||||
if (nestedPathToQuery) {
|
||||
const relatedCollection = payload.collections[matchedField.relationTo as string].config;
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const remainingPaths = await getLocalizedPaths({
|
||||
payload,
|
||||
locale,
|
||||
globalSlug,
|
||||
collectionSlug: relatedCollection.slug,
|
||||
fields: relatedCollection.fields,
|
||||
incomingPath: nestedPathToQuery,
|
||||
});
|
||||
|
||||
paths = [
|
||||
...paths,
|
||||
...remainingPaths,
|
||||
];
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if ('fields' in lastIncompletePath.field) {
|
||||
lastIncompletePath.fields = flattenFields(lastIncompletePath.field.fields, false);
|
||||
}
|
||||
|
||||
if (i + 1 === pathSegments.length) lastIncompletePath.complete = true;
|
||||
lastIncompletePath.path = currentPath;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lastIncompletePath.invalid = true;
|
||||
lastIncompletePath.path = currentPath;
|
||||
return paths;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/* eslint-disable no-restricted-syntax, no-await-in-loop */
|
||||
import fs from 'fs';
|
||||
import { migrationTemplate } from './migrationTemplate';
|
||||
import { CreateMigration } from '../types';
|
||||
|
||||
export const createMigration: CreateMigration = async function createMigration({
|
||||
payload,
|
||||
migrationDir,
|
||||
migrationName,
|
||||
}) {
|
||||
const dir = migrationDir || '.migrations'; // TODO: Verify path after linking
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir);
|
||||
}
|
||||
|
||||
const [yyymmdd, hhmmss] = new Date().toISOString().split('T');
|
||||
const formattedDate = yyymmdd.replace(/\D/g, '');
|
||||
const formattedTime = hhmmss.split('.')[0].replace(/\D/g, '');
|
||||
|
||||
const timestamp = `${formattedDate}_${formattedTime}`;
|
||||
|
||||
const formattedName = migrationName.replace(/\W/g, '_');
|
||||
const fileName = `${timestamp}_${formattedName}.ts`;
|
||||
const filePath = `${dir}/${fileName}`;
|
||||
fs.writeFileSync(filePath, migrationTemplate);
|
||||
payload.logger.info({ msg: `Migration created at ${filePath}` });
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
import { Payload } from '../..';
|
||||
import { MigrationData } from '../types';
|
||||
|
||||
export async function getMigrations({
|
||||
payload,
|
||||
}: {
|
||||
payload: Payload;
|
||||
}): Promise<{ existingMigrations: MigrationData[], latestBatch: number }> {
|
||||
const migrationQuery = await payload.find({
|
||||
collection: 'payload-migrations',
|
||||
sort: '-name',
|
||||
});
|
||||
|
||||
const existingMigrations = migrationQuery.docs as unknown as MigrationData[];
|
||||
|
||||
// Get the highest batch number from existing migrations
|
||||
const latestBatch = existingMigrations?.[0]?.batch || 0;
|
||||
|
||||
return {
|
||||
existingMigrations,
|
||||
latestBatch,
|
||||
};
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* eslint-disable no-restricted-syntax, no-await-in-loop */
|
||||
import { DatabaseAdapter } from '../types';
|
||||
import { getMigrations } from './getMigrations';
|
||||
import { readMigrationFiles } from './readMigrationFiles';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
|
||||
export async function migrate(this: DatabaseAdapter): Promise<void> {
|
||||
const { payload } = this;
|
||||
const migrationFiles = await readMigrationFiles({ payload });
|
||||
const { existingMigrations, latestBatch } = await getMigrations({ payload });
|
||||
|
||||
const newBatch = latestBatch + 1;
|
||||
|
||||
// Execute 'up' function for each migration sequentially
|
||||
for (const migration of migrationFiles) {
|
||||
const existingMigration = existingMigrations.find((existing) => existing.name === migration.name);
|
||||
|
||||
// Run migration if not found in database
|
||||
if (existingMigration) {
|
||||
continue; // eslint-disable-line no-continue
|
||||
}
|
||||
|
||||
const start = Date.now();
|
||||
let transactionID;
|
||||
|
||||
try {
|
||||
payload.logger.info({ msg: `Migrating: ${migration.name}` });
|
||||
transactionID = await this.beginTransaction();
|
||||
await migration.up({ payload });
|
||||
payload.logger.info({ msg: `Migrated: ${migration.name} (${Date.now() - start}ms)` });
|
||||
await payload.create({
|
||||
collection: 'payload-migrations',
|
||||
data: {
|
||||
name: migration.name,
|
||||
batch: newBatch,
|
||||
},
|
||||
req: {
|
||||
transactionID,
|
||||
} as PayloadRequest,
|
||||
});
|
||||
await this.commitTransaction(transactionID);
|
||||
} catch (err: unknown) {
|
||||
await this.rollbackTransaction(transactionID);
|
||||
payload.logger.error({ msg: `Error running migration ${migration.name}`, err });
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/* eslint-disable no-restricted-syntax, no-await-in-loop */
|
||||
import { DatabaseAdapter } from '../types';
|
||||
import { getMigrations } from './getMigrations';
|
||||
import { readMigrationFiles } from './readMigrationFiles';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
|
||||
export async function migrateDown(this: DatabaseAdapter): Promise<void> {
|
||||
const { payload } = this;
|
||||
const migrationFiles = await readMigrationFiles({ payload });
|
||||
|
||||
const {
|
||||
existingMigrations,
|
||||
latestBatch,
|
||||
} = await getMigrations({
|
||||
payload,
|
||||
});
|
||||
|
||||
|
||||
const migrationsToRollback = existingMigrations.filter((migration) => migration.batch === latestBatch);
|
||||
if (!migrationsToRollback?.length) {
|
||||
payload.logger.info({ msg: 'No migrations to rollback.' });
|
||||
return;
|
||||
}
|
||||
payload.logger.info({ msg: `Rolling back batch ${latestBatch} consisting of ${migrationsToRollback.length} migrations.` });
|
||||
|
||||
for (const migration of migrationsToRollback) {
|
||||
const migrationFile = migrationFiles.find((m) => m.name === migration.name);
|
||||
if (!migrationFile) {
|
||||
throw new Error(`Migration ${migration.name} not found locally.`);
|
||||
}
|
||||
|
||||
const start = Date.now();
|
||||
let transactionID;
|
||||
|
||||
try {
|
||||
payload.logger.info({ msg: `Migrating: ${migrationFile.name}` });
|
||||
transactionID = await this.beginTransaction();
|
||||
await migrationFile.down({ payload });
|
||||
payload.logger.info({ msg: `Migrated: ${migrationFile.name} (${Date.now() - start}ms)` });
|
||||
await payload.delete({
|
||||
collection: 'payload-migrations',
|
||||
id: migration.id,
|
||||
req: {
|
||||
transactionID,
|
||||
} as PayloadRequest,
|
||||
});
|
||||
await this.commitTransaction(transactionID);
|
||||
} catch (err: unknown) {
|
||||
await this.rollbackTransaction(transactionID);
|
||||
payload.logger.error({
|
||||
msg: `Error running migration ${migrationFile.name}`,
|
||||
err,
|
||||
});
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* eslint-disable no-restricted-syntax, no-await-in-loop */
|
||||
import { DatabaseAdapter } from '../types';
|
||||
import { readMigrationFiles } from './readMigrationFiles';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
|
||||
/**
|
||||
* Reset and re-run all migrations.
|
||||
*/
|
||||
export async function migrateRefresh(this: DatabaseAdapter) {
|
||||
const { payload } = this;
|
||||
const migrationFiles = await readMigrationFiles({ payload });
|
||||
|
||||
// Clear all migrations
|
||||
await payload.delete({
|
||||
collection: 'payload-migrations',
|
||||
where: {}, // All migrations
|
||||
});
|
||||
let transactionID;
|
||||
// Run all migrations
|
||||
for (const migration of migrationFiles) {
|
||||
payload.logger.info({ msg: `Migrating: ${migration.name}` });
|
||||
try {
|
||||
const start = Date.now();
|
||||
transactionID = await this.beginTransaction();
|
||||
await migration.up({ payload });
|
||||
await payload.create({
|
||||
collection: 'payload-migrations',
|
||||
data: {
|
||||
name: migration.name,
|
||||
executed: true,
|
||||
},
|
||||
req: {
|
||||
transactionID,
|
||||
} as PayloadRequest,
|
||||
});
|
||||
await this.commitTransaction(transactionID);
|
||||
|
||||
payload.logger.info({ msg: `Migrated: ${migration.name} (${Date.now() - start}ms)` });
|
||||
} catch (err: unknown) {
|
||||
await this.rollbackTransaction(transactionID);
|
||||
payload.logger.error({
|
||||
msg: `Error running migration ${migration.name}`,
|
||||
err,
|
||||
});
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* eslint-disable no-restricted-syntax, no-await-in-loop */
|
||||
import { DatabaseAdapter } from '../types';
|
||||
import { getMigrations } from './getMigrations';
|
||||
import { readMigrationFiles } from './readMigrationFiles';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
|
||||
export async function migrateReset(this: DatabaseAdapter): Promise<void> {
|
||||
const { payload } = this;
|
||||
const migrationFiles = await readMigrationFiles({ payload });
|
||||
|
||||
const { existingMigrations } = await getMigrations({ payload });
|
||||
|
||||
if (!existingMigrations?.length) {
|
||||
payload.logger.info({ msg: 'No migrations to reset.' });
|
||||
return;
|
||||
}
|
||||
|
||||
let transactionID;
|
||||
|
||||
// Rollback all migrations in order
|
||||
for (const migration of migrationFiles) {
|
||||
// Create or update migration in database
|
||||
const existingMigration = existingMigrations.find((existing) => existing.name === migration.name);
|
||||
if (existingMigration) {
|
||||
payload.logger.info({ msg: `Migrating: ${migration.name}` });
|
||||
try {
|
||||
const start = Date.now();
|
||||
transactionID = await this.beginTransaction();
|
||||
await migration.down({ payload });
|
||||
await payload.delete({
|
||||
collection: 'payload-migrations',
|
||||
where: {
|
||||
id: {
|
||||
equals: existingMigration.id,
|
||||
},
|
||||
},
|
||||
req: { transactionID } as PayloadRequest,
|
||||
});
|
||||
await this.commitTransaction(transactionID);
|
||||
payload.logger.info({ msg: `Migrated: ${migration.name} (${Date.now() - start}ms)` });
|
||||
} catch (err: unknown) {
|
||||
await this.rollbackTransaction(transactionID);
|
||||
payload.logger.error({ msg: `Error running migration ${migration.name}`, err });
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { Table } from 'console-table-printer';
|
||||
import { DatabaseAdapter } from '../types';
|
||||
import { readMigrationFiles } from './readMigrationFiles';
|
||||
import { getMigrations } from './getMigrations';
|
||||
|
||||
export async function migrateStatus(this: DatabaseAdapter): Promise<void> {
|
||||
const { payload } = this;
|
||||
const migrationFiles = await readMigrationFiles({ payload });
|
||||
const { existingMigrations } = await getMigrations({ payload });
|
||||
|
||||
if (!migrationFiles.length) {
|
||||
payload.logger.info({ msg: 'No migrations found.' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Compare migration files to existing migrations
|
||||
const statuses = migrationFiles.map((migration) => {
|
||||
const existingMigration = existingMigrations.find(
|
||||
(m) => m.name === migration.name,
|
||||
);
|
||||
return {
|
||||
Ran: existingMigration ? 'Yes' : 'No',
|
||||
Name: migration.name,
|
||||
Batch: existingMigration?.batch,
|
||||
};
|
||||
});
|
||||
|
||||
const p = new Table();
|
||||
|
||||
statuses.forEach((s) => {
|
||||
p.addRow(s, {
|
||||
color: s.Ran === 'Yes' ? 'green' : 'red',
|
||||
});
|
||||
});
|
||||
p.printTable();
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export const migrationTemplate = `
|
||||
import payload, { Payload } from 'payload';
|
||||
|
||||
export async function up(payload: Payload): Promise<void> {
|
||||
// Migration code
|
||||
};
|
||||
|
||||
export async function down(payload: Payload): Promise<void> {
|
||||
// Migration code
|
||||
};
|
||||
`;
|
||||
@@ -1,39 +0,0 @@
|
||||
import type { CollectionConfig } from '../../collections/config/types';
|
||||
|
||||
export const migrationsCollection: CollectionConfig = {
|
||||
slug: 'payload-migrations',
|
||||
admin: {
|
||||
hidden: true,
|
||||
},
|
||||
graphQL: false,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'batch',
|
||||
type: 'number',
|
||||
},
|
||||
// TODO: determine how schema will impact migration workflow
|
||||
{
|
||||
name: 'schema',
|
||||
type: 'json',
|
||||
},
|
||||
// TODO: do we need to persist the indexes separate from the schema?
|
||||
// {
|
||||
// name: 'indexes',
|
||||
// type: 'array',
|
||||
// fields: [
|
||||
// {
|
||||
// name: 'index',
|
||||
// type: 'text',
|
||||
// },
|
||||
// {
|
||||
// name: 'value',
|
||||
// type: 'json',
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { Migration } from '../types';
|
||||
import { Payload } from '../../index';
|
||||
|
||||
/**
|
||||
* Read the migration files from disk
|
||||
*/
|
||||
export const readMigrationFiles = async ({
|
||||
payload,
|
||||
}: {
|
||||
payload: Payload;
|
||||
}): Promise<Migration[]> => {
|
||||
if (!fs.existsSync(payload.db.migrationDir)) return [];
|
||||
|
||||
const files = fs
|
||||
.readdirSync(payload.db.migrationDir)
|
||||
.sort()
|
||||
.map((file) => {
|
||||
return path.resolve(payload.db.migrationDir, file);
|
||||
});
|
||||
return files.map((filePath) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires,import/no-dynamic-require
|
||||
const migration = require(filePath) as Migration;
|
||||
migration.name = path.basename(filePath).split('.')?.[0];
|
||||
return migration;
|
||||
});
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
import { CollectionPermission, GlobalPermission } from '../../auth';
|
||||
import { Field, FieldAffectingData, TabAsField, UIField } from '../../fields/config/types';
|
||||
|
||||
export const validOperators = ['like', 'contains', 'in', 'all', 'not_in', 'greater_than_equal', 'greater_than', 'less_than_equal', 'less_than', 'not_equals', 'equals', 'exists', 'near'];
|
||||
|
||||
export type EntityPolicies = {
|
||||
collections?: {
|
||||
[collectionSlug: string]: CollectionPermission;
|
||||
};
|
||||
globals?: {
|
||||
[globalSlug: string]: GlobalPermission;
|
||||
};
|
||||
};
|
||||
|
||||
export type PathToQuery = {
|
||||
complete: boolean
|
||||
collectionSlug?: string
|
||||
globalSlug?: string
|
||||
path: string
|
||||
field: Field | TabAsField
|
||||
fields?: (FieldAffectingData | UIField | TabAsField)[]
|
||||
invalid?: boolean
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import { PayloadRequest, Where, WhereField } from '../../types';
|
||||
import QueryError from '../../errors/QueryError';
|
||||
import { SanitizedCollectionConfig } from '../../collections/config/types';
|
||||
import { SanitizedGlobalConfig } from '../../globals/config/types';
|
||||
import flattenFields from '../../utilities/flattenTopLevelFields';
|
||||
import { Field, FieldAffectingData } from '../../fields/config/types';
|
||||
import { validateSearchParam } from './validateSearchParams';
|
||||
import deepCopyObject from '../../utilities/deepCopyObject';
|
||||
import { EntityPolicies, validOperators } from './types';
|
||||
|
||||
const flattenWhere = (query: Where): WhereField[] => Object.entries(query).reduce((flattenedConstraints, [key, val]) => {
|
||||
if ((key === 'and' || key === 'or') && Array.isArray(val)) {
|
||||
return [
|
||||
...flattenedConstraints,
|
||||
...val.map((subVal) => flattenWhere(subVal)),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
...flattenedConstraints,
|
||||
{ [key]: val },
|
||||
];
|
||||
}, []);
|
||||
|
||||
type Args = {
|
||||
where: Where
|
||||
errors?: { path: string }[]
|
||||
policies?: EntityPolicies
|
||||
req: PayloadRequest
|
||||
versionFields?: Field[]
|
||||
overrideAccess: boolean
|
||||
} & ({
|
||||
collectionConfig: SanitizedCollectionConfig
|
||||
globalConfig?: never | undefined
|
||||
} | {
|
||||
globalConfig: SanitizedGlobalConfig
|
||||
collectionConfig?: never | undefined
|
||||
})
|
||||
export async function validateQueryPaths({
|
||||
where,
|
||||
collectionConfig,
|
||||
globalConfig,
|
||||
errors = [],
|
||||
policies = {
|
||||
collections: {},
|
||||
globals: {},
|
||||
},
|
||||
versionFields,
|
||||
req,
|
||||
overrideAccess,
|
||||
}: Args): Promise<void> {
|
||||
const fields = flattenFields(versionFields || (globalConfig || collectionConfig).fields) as FieldAffectingData[];
|
||||
if (typeof where === 'object') {
|
||||
// const flattenedWhere = flattenWhere(where);
|
||||
const whereFields = flattenWhere(where);
|
||||
// We need to determine if the whereKey is an AND, OR, or a schema path
|
||||
const promises = [];
|
||||
whereFields.map(async (constraint) => {
|
||||
Object.keys(constraint).map(async (path) => {
|
||||
Object.entries(constraint[path]).map(async ([operator, val]) => {
|
||||
if (validOperators.includes(operator)) {
|
||||
promises.push(validateSearchParam({
|
||||
collectionConfig: deepCopyObject(collectionConfig),
|
||||
globalConfig: deepCopyObject(globalConfig),
|
||||
fields: (fields as Field[]),
|
||||
versionFields,
|
||||
errors,
|
||||
policies,
|
||||
req,
|
||||
path,
|
||||
val,
|
||||
operator,
|
||||
overrideAccess,
|
||||
}));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
await Promise.all(promises);
|
||||
if (errors.length > 0) {
|
||||
throw new QueryError(errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
import { Field, fieldAffectsData } from '../../fields/config/types';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
import { getEntityPolicies } from '../../utilities/getEntityPolicies';
|
||||
import { SanitizedCollectionConfig } from '../../collections/config/types';
|
||||
import { SanitizedGlobalConfig } from '../../globals/config/types';
|
||||
import { validateQueryPaths } from './validateQueryPaths';
|
||||
import { EntityPolicies, PathToQuery } from './types';
|
||||
import { getLocalizedPaths } from '../getLocalizedPaths';
|
||||
|
||||
type Args = {
|
||||
fields: Field[]
|
||||
path: string
|
||||
val: unknown
|
||||
operator: string
|
||||
req: PayloadRequest
|
||||
errors: { path: string }[]
|
||||
policies: EntityPolicies
|
||||
collectionConfig?: SanitizedCollectionConfig
|
||||
globalConfig?: SanitizedGlobalConfig
|
||||
versionFields?: Field[]
|
||||
overrideAccess: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the Payload key / value / operator
|
||||
*/
|
||||
export async function validateSearchParam({
|
||||
fields,
|
||||
path: incomingPath,
|
||||
versionFields,
|
||||
val,
|
||||
operator,
|
||||
collectionConfig,
|
||||
globalConfig,
|
||||
errors,
|
||||
req,
|
||||
policies,
|
||||
overrideAccess,
|
||||
}: Args): Promise<void> {
|
||||
// Replace GraphQL nested field double underscore formatting
|
||||
let sanitizedPath;
|
||||
if (incomingPath === '_id') {
|
||||
sanitizedPath = 'id';
|
||||
} else {
|
||||
sanitizedPath = incomingPath.replace(/__/gi, '.');
|
||||
}
|
||||
let paths: PathToQuery[] = [];
|
||||
const { slug } = (collectionConfig || globalConfig);
|
||||
|
||||
if (globalConfig && !policies.globals[slug]) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
globalConfig.fields = fields;
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
policies.globals[slug] = await getEntityPolicies({
|
||||
req,
|
||||
entity: globalConfig,
|
||||
operations: ['read'],
|
||||
type: 'global',
|
||||
});
|
||||
}
|
||||
|
||||
if (sanitizedPath !== 'id') {
|
||||
paths = await getLocalizedPaths({
|
||||
payload: req.payload,
|
||||
locale: req.locale,
|
||||
collectionSlug: collectionConfig?.slug,
|
||||
globalSlug: globalConfig?.slug,
|
||||
fields,
|
||||
incomingPath: sanitizedPath,
|
||||
overrideAccess,
|
||||
});
|
||||
}
|
||||
const promises = [];
|
||||
promises.push(...paths.map(async ({ path, field, invalid, collectionSlug }, i) => {
|
||||
if (invalid) {
|
||||
errors.push({ path });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!overrideAccess && fieldAffectsData(field)) {
|
||||
if (collectionSlug) {
|
||||
if (!policies.collections[collectionSlug]) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
policies.collections[collectionSlug] = await getEntityPolicies({
|
||||
req,
|
||||
entity: req.payload.collections[collectionSlug].config,
|
||||
operations: ['read'],
|
||||
type: 'collection',
|
||||
});
|
||||
}
|
||||
|
||||
if (['salt', 'hash'].includes(incomingPath) && collectionConfig.auth && !collectionConfig.auth?.disableLocalStrategy) {
|
||||
errors.push({ path: incomingPath });
|
||||
}
|
||||
}
|
||||
let fieldAccess;
|
||||
let fieldPath = path;
|
||||
// remove locale from end of path
|
||||
if (path.endsWith(req.locale)) {
|
||||
fieldPath = path.slice(0, -(req.locale.length + 1));
|
||||
}
|
||||
// remove ".value" from ends of polymorphic relationship paths
|
||||
if (field.type === 'relationship' && Array.isArray(field.relationTo)) {
|
||||
fieldPath = fieldPath.replace('.value', '');
|
||||
}
|
||||
const entityType: 'collections' | 'globals' = globalConfig ? 'globals' : 'collections';
|
||||
const entitySlug = collectionSlug || globalConfig.slug;
|
||||
const segments = fieldPath.split('.');
|
||||
|
||||
if (versionFields) {
|
||||
if (fieldPath === 'parent' || fieldPath === 'version') {
|
||||
fieldAccess = policies[entityType][entitySlug].read.permission;
|
||||
} else if (segments[0] === 'parent' || segments[0] === 'version') {
|
||||
fieldAccess = policies[entityType][entitySlug].read.permission;
|
||||
segments.shift();
|
||||
}
|
||||
} else {
|
||||
fieldAccess = policies[entityType][entitySlug].fields;
|
||||
segments.forEach((segment, pathIndex) => {
|
||||
if (pathIndex === segments.length - 1) {
|
||||
fieldAccess = fieldAccess[segment];
|
||||
} else {
|
||||
fieldAccess = fieldAccess[segment].fields;
|
||||
}
|
||||
});
|
||||
fieldAccess = fieldAccess.read.permission;
|
||||
}
|
||||
if (!fieldAccess) {
|
||||
errors.push({ path: fieldPath });
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 1) {
|
||||
// Remove top collection and reverse array
|
||||
// to work backwards from top
|
||||
const pathsToQuery = paths.slice(1)
|
||||
.reverse();
|
||||
|
||||
pathsToQuery.forEach(({
|
||||
path: subPath,
|
||||
collectionSlug: pathCollectionSlug,
|
||||
}, pathToQueryIndex) => {
|
||||
// On the "deepest" collection,
|
||||
// validate query of the relationship
|
||||
if (pathToQueryIndex === 0) {
|
||||
promises.push(validateQueryPaths({
|
||||
collectionConfig: req.payload.collections[pathCollectionSlug].config,
|
||||
globalConfig: undefined,
|
||||
where: {
|
||||
[subPath]: {
|
||||
[operator]: val,
|
||||
},
|
||||
},
|
||||
errors,
|
||||
policies,
|
||||
req,
|
||||
overrideAccess,
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { Transaction } from './types';
|
||||
|
||||
export const transaction: Transaction = async function transaction(
|
||||
callback: () => Promise<unknown>,
|
||||
options,
|
||||
) {
|
||||
const id = await this.beginTransaction(options);
|
||||
try {
|
||||
await callback();
|
||||
await this.commitTransaction(id);
|
||||
} catch (err: unknown) {
|
||||
await this.rollbackTransaction(id);
|
||||
}
|
||||
};
|
||||
@@ -1,354 +0,0 @@
|
||||
import type { Configuration } from 'webpack';
|
||||
import type { TypeWithID } from '../collections/config/types';
|
||||
import type { TypeWithID as GlobalsTypeWithID } from '../globals/config/types';
|
||||
import type { Payload } from '../payload';
|
||||
import type { Document, PayloadRequest, Where } from '../types';
|
||||
import type { TypeWithVersion } from '../versions/types';
|
||||
|
||||
export interface DatabaseAdapter {
|
||||
/**
|
||||
* reference to the instance of payload
|
||||
*/
|
||||
payload: Payload;
|
||||
/**
|
||||
* Open the connection to the database
|
||||
*/
|
||||
connect?: Connect;
|
||||
|
||||
/**
|
||||
* Perform startup tasks required to interact with the database such as building Schema and models
|
||||
*/
|
||||
init?: Init;
|
||||
|
||||
/**
|
||||
* Terminate the connection with the database
|
||||
*/
|
||||
destroy?: Destroy;
|
||||
|
||||
/**
|
||||
* Used to alias server only modules or make other changes to webpack configuration
|
||||
*/
|
||||
webpack?: Webpack;
|
||||
|
||||
// migrations
|
||||
/**
|
||||
* Path to read and write migration files from
|
||||
*/
|
||||
migrationDir?: string;
|
||||
|
||||
/**
|
||||
* Output a migration file
|
||||
*/
|
||||
createMigration: (CreateMigrationArgs) => Promise<void>;
|
||||
|
||||
/**
|
||||
* Run any migration up functions that have not yet been performed and update the status
|
||||
*/
|
||||
migrate: () => Promise<void>;
|
||||
|
||||
/**
|
||||
* Read the current state of migrations and output the result to show which have been run
|
||||
*/
|
||||
migrateStatus: () => Promise<void>;
|
||||
|
||||
/**
|
||||
* Run any migration down functions that have been performed
|
||||
*/
|
||||
migrateDown: () => Promise<void>;
|
||||
|
||||
/**
|
||||
* Run all migration down functions before running up
|
||||
*/
|
||||
migrateRefresh: () => Promise<void>;
|
||||
|
||||
/**
|
||||
* Run all migrate down functions
|
||||
*/
|
||||
migrateReset: () => Promise<void>;
|
||||
|
||||
/**
|
||||
* Drop the current database and run all migrate up functions
|
||||
*/
|
||||
migrateFresh: () => Promise<void>;
|
||||
|
||||
// transactions
|
||||
/**
|
||||
* assign the transaction to use when making queries, defaults to the last started transaction
|
||||
*/
|
||||
useTransaction?: (id: string | number) => void;
|
||||
|
||||
/**
|
||||
* Perform many database interactions in a single, all-or-nothing operation.
|
||||
*/
|
||||
transaction?: Transaction;
|
||||
|
||||
/**
|
||||
* Start a transaction, requiring commitTransaction() to be called for any changes to be made.
|
||||
* @returns an identifier for the transaction or null if one cannot be established
|
||||
*/
|
||||
beginTransaction?: BeginTransaction;
|
||||
|
||||
/**
|
||||
* Abort any changes since the start of the transaction.
|
||||
*/
|
||||
rollbackTransaction?: RollbackTransaction;
|
||||
|
||||
/**
|
||||
* Persist the changes made since the start of the transaction.
|
||||
*/
|
||||
commitTransaction?: CommitTransaction;
|
||||
|
||||
queryDrafts: QueryDrafts;
|
||||
|
||||
// operations
|
||||
find: <T = TypeWithID>(args: FindArgs) => Promise<PaginatedDocs<T>>;
|
||||
findOne: FindOne;
|
||||
|
||||
create: Create;
|
||||
updateOne: UpdateOne;
|
||||
deleteOne: DeleteOne;
|
||||
deleteMany: DeleteMany;
|
||||
|
||||
// operations - globals
|
||||
findGlobal: FindGlobal;
|
||||
createGlobal: CreateGlobal;
|
||||
updateGlobal: UpdateGlobal;
|
||||
|
||||
|
||||
// versions
|
||||
findVersions: FindVersions;
|
||||
findGlobalVersions: FindGlobalVersions;
|
||||
createVersion: CreateVersion;
|
||||
updateVersion: UpdateVersion;
|
||||
deleteVersions: DeleteVersions;
|
||||
}
|
||||
|
||||
export type Init = (payload: Payload) => Promise<void>;
|
||||
|
||||
export type Connect = (payload: Payload) => Promise<void>
|
||||
|
||||
export type Destroy = (payload: Payload) => Promise<void>
|
||||
|
||||
export type Webpack = (config: Configuration) => Configuration;
|
||||
|
||||
export type CreateMigrationArgs = {
|
||||
payload: Payload
|
||||
migrationDir: string
|
||||
migrationName: string
|
||||
}
|
||||
|
||||
export type CreateMigration = (args: CreateMigrationArgs) => Promise<void>
|
||||
|
||||
export type Transaction = (callback: () => Promise<void>, options?: Record<string, unknown>) => Promise<void>
|
||||
|
||||
export type BeginTransaction = (options?: Record<string, unknown>) => Promise<number | string | null>
|
||||
|
||||
export type RollbackTransaction = (id: string | number) => Promise<void>
|
||||
|
||||
export type CommitTransaction = (id: string | number) => Promise<void>
|
||||
|
||||
export type QueryDraftsArgs = {
|
||||
collection: string
|
||||
where?: Where
|
||||
page?: number
|
||||
limit?: number
|
||||
pagination?: boolean
|
||||
sort?: string
|
||||
locale?: string
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type QueryDrafts = <T = TypeWithID>(args: QueryDraftsArgs) => Promise<PaginatedDocs<T>>;
|
||||
|
||||
export type FindOneArgs = {
|
||||
collection: string
|
||||
where?: Where
|
||||
locale?: string
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
|
||||
export type FindOne = <T = TypeWithID>(args: FindOneArgs) => Promise<T | null>
|
||||
|
||||
export type FindArgs = {
|
||||
collection: string
|
||||
where?: Where
|
||||
page?: number
|
||||
skip?: number
|
||||
versions?: boolean
|
||||
/** Setting limit to 1 is equal to the previous Model.findOne(). Setting limit to 0 disables the limit */
|
||||
limit?: number
|
||||
pagination?: boolean
|
||||
sort?: string
|
||||
locale?: string
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type Find = <T = TypeWithID>(args: FindArgs) => Promise<PaginatedDocs<T>>;
|
||||
|
||||
export type FindVersionsArgs = {
|
||||
collection: string
|
||||
where?: Where
|
||||
page?: number
|
||||
skip?: number
|
||||
versions?: boolean
|
||||
limit?: number
|
||||
pagination?: boolean
|
||||
sort?: string
|
||||
locale?: string
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type FindVersions = <T = TypeWithID>(args: FindVersionsArgs) => Promise<PaginatedDocs<TypeWithVersion<T>>>;
|
||||
|
||||
|
||||
export type FindGlobalVersionsArgs = {
|
||||
global: string
|
||||
where?: Where
|
||||
page?: number
|
||||
skip?: number
|
||||
versions?: boolean
|
||||
limit?: number
|
||||
pagination?: boolean
|
||||
sort?: string
|
||||
locale?: string
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type FindGlobalArgs = {
|
||||
slug: string
|
||||
locale?: string
|
||||
where?: Where
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type FindGlobal = <T extends GlobalsTypeWithID = any>(args: FindGlobalArgs) => Promise<T>
|
||||
|
||||
|
||||
export type CreateGlobalArgs<T extends GlobalsTypeWithID = any> = {
|
||||
slug: string
|
||||
data: T
|
||||
req?: PayloadRequest
|
||||
}
|
||||
export type CreateGlobal = <T extends GlobalsTypeWithID = any>(args: CreateGlobalArgs<T>) => Promise<T>
|
||||
|
||||
|
||||
export type UpdateGlobalArgs<T extends GlobalsTypeWithID = any> = {
|
||||
slug: string
|
||||
data: T
|
||||
req?: PayloadRequest
|
||||
}
|
||||
export type UpdateGlobal = <T extends GlobalsTypeWithID = any>(args: UpdateGlobalArgs<T>) => Promise<T>
|
||||
// export type UpdateOne = (args: UpdateOneArgs) => Promise<Document>
|
||||
|
||||
export type FindGlobalVersions = <T = TypeWithID>(args: FindGlobalVersionsArgs) => Promise<PaginatedDocs<TypeWithVersion<T>>>;
|
||||
|
||||
export type DeleteVersionsArgs = {
|
||||
collection: string
|
||||
where: Where
|
||||
locale?: string
|
||||
sort?: {
|
||||
[key: string]: string
|
||||
}
|
||||
req?: PayloadRequest
|
||||
};
|
||||
|
||||
export type CreateVersionArgs<T = TypeWithID> = {
|
||||
collectionSlug: string
|
||||
/** ID of the parent document for which the version should be created for */
|
||||
parent: string | number
|
||||
versionData: T
|
||||
autosave: boolean
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type CreateVersion = <T = TypeWithID>(args: CreateVersionArgs<T>) => Promise<TypeWithVersion<T>>;
|
||||
|
||||
export type DeleteVersions = (args: DeleteVersionsArgs) => Promise<void>;
|
||||
|
||||
|
||||
export type UpdateVersionArgs<T = TypeWithID> = {
|
||||
collectionSlug: string
|
||||
where: Where
|
||||
locale?: string
|
||||
versionData: T
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type UpdateVersion = <T = TypeWithID>(args: UpdateVersionArgs<T>) => Promise<TypeWithVersion<T>>
|
||||
|
||||
|
||||
export type CreateArgs = {
|
||||
collection: string
|
||||
data: Record<string, unknown>
|
||||
draft?: boolean
|
||||
locale?: string
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type Create = (args: CreateArgs) => Promise<Document>
|
||||
|
||||
export type UpdateArgs = {
|
||||
collection: string
|
||||
data: Record<string, unknown>
|
||||
where: Where
|
||||
draft?: boolean
|
||||
locale?: string
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type Update = (args: UpdateArgs) => Promise<Document>
|
||||
|
||||
export type UpdateOneArgs = {
|
||||
collection: string
|
||||
data: Record<string, unknown>
|
||||
where: Where
|
||||
draft?: boolean
|
||||
locale?: string
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type UpdateOne = (args: UpdateOneArgs) => Promise<Document>
|
||||
|
||||
export type DeleteOneArgs = {
|
||||
collection: string
|
||||
where: Where
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type DeleteOne = (args: DeleteOneArgs) => Promise<Document>
|
||||
|
||||
export type DeleteManyArgs = {
|
||||
collection: string
|
||||
where: Where
|
||||
req?: PayloadRequest
|
||||
}
|
||||
|
||||
export type DeleteMany = (args: DeleteManyArgs) => Promise<void>
|
||||
|
||||
|
||||
export type Migration = MigrationData & {
|
||||
up: ({ payload }: { payload }) => Promise<boolean>
|
||||
down: ({ payload }: { payload }) => Promise<boolean>
|
||||
};
|
||||
|
||||
export type MigrationData = {
|
||||
id: string
|
||||
name: string
|
||||
batch: number
|
||||
}
|
||||
|
||||
export type PaginatedDocs<T = any> = {
|
||||
docs: T[]
|
||||
totalDocs: number
|
||||
limit: number
|
||||
totalPages: number
|
||||
page?: number
|
||||
pagingCounter: number
|
||||
hasPrevPage: boolean
|
||||
hasNextPage: boolean
|
||||
prevPage?: number | null | undefined
|
||||
nextPage?: number | null | undefined
|
||||
}
|
||||
@@ -5,7 +5,7 @@ async function initAdmin(ctx: Payload): Promise<void> {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
ctx.express.use(ctx.config.routes.admin, await ctx.config.admin.bundler.serve(ctx));
|
||||
} else {
|
||||
ctx.express.use(ctx.config.routes.admin, await ctx.config.admin.bundler.dev(ctx));
|
||||
ctx.express.use(await ctx.config.admin.bundler.dev(ctx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import type { Response, NextFunction } from 'express';
|
||||
import type { PayloadRequest } from '../types';
|
||||
import { setRequestContext } from '../setRequestContext';
|
||||
|
||||
function defaultPayload(req: PayloadRequest, res: Response, next: NextFunction) {
|
||||
setRequestContext(req);
|
||||
next();
|
||||
}
|
||||
|
||||
export default defaultPayload;
|
||||
@@ -21,11 +21,11 @@ const errorHandler = (config: SanitizedConfig, logger: Logger) => async (err: AP
|
||||
}
|
||||
|
||||
if (req.collection && typeof req.collection.config.hooks.afterError === 'function') {
|
||||
({ response, status } = await req.collection.config.hooks.afterError(err, response, req.context) || { response, status });
|
||||
({ response, status } = await req.collection.config.hooks.afterError(err, response) || { response, status });
|
||||
}
|
||||
|
||||
if (typeof config.hooks.afterError === 'function') {
|
||||
({ response, status } = await config.hooks.afterError(err, response, req.context) || { response, status });
|
||||
({ response, status } = await config.hooks.afterError(err, response) || { response, status });
|
||||
}
|
||||
|
||||
res.status(status).send(response);
|
||||
|
||||
@@ -14,7 +14,6 @@ import { PayloadRequest } from '../types';
|
||||
import corsHeaders from './corsHeaders';
|
||||
import convertPayload from './convertPayload';
|
||||
import { i18nMiddleware } from './i18n';
|
||||
import defaultPayload from './defaultPayload';
|
||||
|
||||
const middleware = (payload: Payload): any => {
|
||||
const rateLimitOptions: {
|
||||
@@ -33,7 +32,6 @@ const middleware = (payload: Payload): any => {
|
||||
}
|
||||
|
||||
return [
|
||||
defaultPayload,
|
||||
...(payload.config.express.preMiddleware || []),
|
||||
rateLimit(rateLimitOptions),
|
||||
passport.initialize(),
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { PayloadRequest, RequestContext } from './types';
|
||||
|
||||
/**
|
||||
* This makes sure that req.context always exists (is {}) and populates it with an optional default context.
|
||||
* This function mutates directly to avoid copying memory. As payloadRequest is not a primitive, the scope of the mutation is not limited to this function but should also be reflected in the calling function.
|
||||
*/
|
||||
export function setRequestContext(req: PayloadRequest = { context: null } as PayloadRequest, context: RequestContext = {}) {
|
||||
if (req.context) {
|
||||
if (Object.keys(req.context).length === 0 && req.context.constructor === Object) { // check if req.context is just {}
|
||||
req.context = context; // Faster - ... is bad for performance
|
||||
} else {
|
||||
req.context = { ...req.context, ...context }; // Merge together
|
||||
}
|
||||
} else {
|
||||
req.context = context;
|
||||
}
|
||||
}
|
||||
@@ -24,20 +24,10 @@ export declare type PayloadRequest<U = any> = Request & {
|
||||
* - Configuration from payload-config.ts
|
||||
* - MongoDB model for this collection
|
||||
* - GraphQL type metadata
|
||||
*/
|
||||
* */
|
||||
collection?: Collection;
|
||||
/** What triggered this request */
|
||||
payloadAPI?: 'REST' | 'local' | 'GraphQL';
|
||||
/**
|
||||
* Identifier for the database transaction for interactions in a single, all-or-nothing operation.
|
||||
*/
|
||||
transactionID?: string | number;
|
||||
/** context allows you to pass your own data to the request object as context
|
||||
* This is useful for, for example, passing data from a beforeChange hook to an afterChange hook.
|
||||
* payoadContext can also be fully typed using declare module
|
||||
* {@link https://payloadcms.com/docs/hooks/context More info in the Payload Documentation}.
|
||||
*/
|
||||
context: RequestContext;
|
||||
/** Uploaded files */
|
||||
files?: {
|
||||
/**
|
||||
@@ -59,7 +49,3 @@ export declare type PayloadRequest<U = any> = Request & {
|
||||
[slug: string]: (q: unknown) => Document;
|
||||
};
|
||||
};
|
||||
|
||||
export interface RequestContext {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { EditorProps } from '@monaco-editor/react';
|
||||
import { Operation, Where } from '../../types';
|
||||
import { SanitizedConfig } from '../../config/types';
|
||||
import { TypeWithID } from '../../collections/config/types';
|
||||
import { PayloadRequest, RequestContext } from '../../express/types';
|
||||
import { PayloadRequest } from '../../express/types';
|
||||
import { ConditionalDateProps } from '../../admin/components/elements/DatePicker/types';
|
||||
import { Description } from '../../admin/components/forms/FieldDescription/types';
|
||||
import { User } from '../../auth';
|
||||
@@ -33,7 +33,6 @@ export type FieldHookArgs<T extends TypeWithID = any, P = any, S = any> = {
|
||||
/** The value of the field. */
|
||||
value?: P,
|
||||
previousValue?: P,
|
||||
context: RequestContext
|
||||
}
|
||||
|
||||
export type FieldHook<T extends TypeWithID = any, P = any, S = any> = (args: FieldHookArgs<T, P, S>) => Promise<P> | P;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SanitizedCollectionConfig } from '../../../collections/config/types';
|
||||
import { SanitizedGlobalConfig } from '../../../globals/config/types';
|
||||
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||
import { PayloadRequest } from '../../../express/types';
|
||||
import { traverseFields } from './traverseFields';
|
||||
import deepCopyObject from '../../../utilities/deepCopyObject';
|
||||
|
||||
@@ -11,7 +11,6 @@ type Args<T> = {
|
||||
entityConfig: SanitizedCollectionConfig | SanitizedGlobalConfig
|
||||
operation: 'create' | 'update'
|
||||
req: PayloadRequest
|
||||
context: RequestContext
|
||||
}
|
||||
|
||||
export const afterChange = async <T extends Record<string, unknown>>({
|
||||
@@ -21,7 +20,6 @@ export const afterChange = async <T extends Record<string, unknown>>({
|
||||
entityConfig,
|
||||
operation,
|
||||
req,
|
||||
context,
|
||||
}: Args<T>): Promise<T> => {
|
||||
const doc = deepCopyObject(incomingDoc);
|
||||
|
||||
@@ -35,7 +33,6 @@ export const afterChange = async <T extends Record<string, unknown>>({
|
||||
previousSiblingDoc: previousDoc,
|
||||
siblingDoc: doc,
|
||||
siblingData: data,
|
||||
context,
|
||||
});
|
||||
|
||||
return doc;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { PayloadRequest, RequestContext } from '../../../express/types';
|
||||
import { PayloadRequest } from '../../../express/types';
|
||||
import { Field, fieldAffectsData, TabAsField, tabHasName } from '../../config/types';
|
||||
import { traverseFields } from './traverseFields';
|
||||
|
||||
@@ -13,7 +13,6 @@ type Args = {
|
||||
req: PayloadRequest
|
||||
siblingData: Record<string, unknown>
|
||||
siblingDoc: Record<string, unknown>
|
||||
context: RequestContext
|
||||
}
|
||||
|
||||
// This function is responsible for the following actions, in order:
|
||||
@@ -29,7 +28,6 @@ export const promise = async ({
|
||||
req,
|
||||
siblingData,
|
||||
siblingDoc,
|
||||
context,
|
||||
}: Args): Promise<void> => {
|
||||
if (fieldAffectsData(field)) {
|
||||
// Execute hooks
|
||||
@@ -47,7 +45,6 @@ export const promise = async ({
|
||||
siblingData,
|
||||
operation,
|
||||
req,
|
||||
context,
|
||||
});
|
||||
|
||||
if (hookedValue !== undefined) {
|
||||
@@ -70,7 +67,6 @@ export const promise = async ({
|
||||
req,
|
||||
siblingData: siblingData?.[field.name] as Record<string, unknown> || {},
|
||||
siblingDoc: siblingDoc[field.name] as Record<string, unknown>,
|
||||
context,
|
||||
});
|
||||
|
||||
break;
|
||||
@@ -92,7 +88,6 @@ export const promise = async ({
|
||||
req,
|
||||
siblingData: siblingData?.[field.name]?.[i] || {},
|
||||
siblingDoc: { ...row } || {},
|
||||
context,
|
||||
}));
|
||||
});
|
||||
await Promise.all(promises);
|
||||
@@ -119,7 +114,6 @@ export const promise = async ({
|
||||
req,
|
||||
siblingData: siblingData?.[field.name]?.[i] || {},
|
||||
siblingDoc: { ...row } || {},
|
||||
context,
|
||||
}));
|
||||
}
|
||||
});
|
||||
@@ -141,7 +135,6 @@ export const promise = async ({
|
||||
req,
|
||||
siblingData: siblingData || {},
|
||||
siblingDoc: { ...siblingDoc },
|
||||
context,
|
||||
});
|
||||
|
||||
break;
|
||||
@@ -168,7 +161,6 @@ export const promise = async ({
|
||||
previousDoc,
|
||||
siblingData: tabSiblingData,
|
||||
siblingDoc: tabSiblingDoc,
|
||||
context,
|
||||
});
|
||||
|
||||
break;
|
||||
@@ -185,7 +177,6 @@ export const promise = async ({
|
||||
req,
|
||||
siblingData: siblingData || {},
|
||||
siblingDoc: { ...siblingDoc },
|
||||
context,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user