Compare commits
9 Commits
test/ts-ty
...
feat/forma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2cd6bbaec | ||
|
|
b2657ed12b | ||
|
|
0851ef99da | ||
|
|
3c483ab57a | ||
|
|
9bdbbb674f | ||
|
|
eb191f335b | ||
|
|
02bb176890 | ||
|
|
082c6ef44a | ||
|
|
f93cdf9364 |
43
.github/workflows/main.yml
vendored
43
.github/workflows/main.yml
vendored
@@ -196,7 +196,6 @@ jobs:
|
||||
- postgres-custom-schema
|
||||
- postgres-uuid
|
||||
- supabase
|
||||
- sqlite
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
@@ -549,45 +548,3 @@ jobs:
|
||||
steps:
|
||||
- if: ${{ always() && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }}
|
||||
run: exit 1
|
||||
|
||||
publish-canary:
|
||||
name: Publish Canary
|
||||
if: github.ref == 'refs/heads/beta'
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- all-green
|
||||
|
||||
steps:
|
||||
# https://github.com/actions/virtual-environments/issues/1187
|
||||
- name: tune linux network
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
|
||||
- name: Setup Node@${{ env.NODE_VERSION }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
run_install: false
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
timeout-minutes: 10
|
||||
with:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}-${{ github.run_number }}
|
||||
|
||||
- name: Load npm token
|
||||
run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Canary release script
|
||||
# dry run hard-coded to true for testing and no npm token provided
|
||||
run: pnpm tsx ./scripts/publish-canary.ts
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_CONFIG_PROVENANCE: true
|
||||
|
||||
1
.github/workflows/pr-title.yml
vendored
1
.github/workflows/pr-title.yml
vendored
@@ -38,7 +38,6 @@ jobs:
|
||||
db-\*
|
||||
db-mongodb
|
||||
db-postgres
|
||||
db-sqlite
|
||||
email-nodemailer
|
||||
eslint
|
||||
graphql
|
||||
|
||||
@@ -266,10 +266,12 @@ export const myField: Field = {
|
||||
|
||||
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
|
||||
|
||||
Custom Label Components receive all [Field Component](#the-field-component) props, plus the following props:
|
||||
All Label Components receive the following props:
|
||||
|
||||
| Property | Description |
|
||||
| -------------- | ---------------------------------------------------------------- |
|
||||
| **`label`** | Label value provided in field, it can be used with i18n. |
|
||||
| **`required`** | The `admin.required` property defined in the [Field Config](../fields/overview). |
|
||||
| **`schemaPath`** | The path to the field in the schema. Similar to `path`, but without dynamic indices. |
|
||||
|
||||
<Banner type="success">
|
||||
@@ -277,36 +279,6 @@ Custom Label Components receive all [Field Component](#the-field-component) prop
|
||||
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
|
||||
</Banner>
|
||||
|
||||
#### TypeScript
|
||||
|
||||
When building Custom Error Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Error Component, one for every [Field Type](../fields/overview). The convention is to append `ErrorComponent` to the type of field, i.e. `TextFieldErrorComponent`.
|
||||
|
||||
```tsx
|
||||
import type {
|
||||
ArrayFieldLabelComponent,
|
||||
BlocksFieldLabelComponent,
|
||||
CheckboxFieldLabelComponent,
|
||||
CodeFieldLabelComponent,
|
||||
CollapsibleFieldLabelComponent,
|
||||
DateFieldLabelComponent,
|
||||
EmailFieldLabelComponent,
|
||||
GroupFieldLabelComponent,
|
||||
HiddenFieldLabelComponent,
|
||||
JSONFieldLabelComponent,
|
||||
NumberFieldLabelComponent,
|
||||
PointFieldLabelComponent,
|
||||
RadioFieldLabelComponent,
|
||||
RelationshipFieldLabelComponent,
|
||||
RichTextFieldLabelComponent,
|
||||
RowFieldLabelComponent,
|
||||
SelectFieldLabelComponent,
|
||||
TabsFieldLabelComponent,
|
||||
TextFieldLabelComponent,
|
||||
TextareaFieldLabelComponent,
|
||||
UploadFieldLabelComponent
|
||||
} from 'payload'
|
||||
```
|
||||
|
||||
### The Error Component
|
||||
|
||||
The Error Component is rendered when a field fails validation. It is typically displayed beneath the field input in a visually-compelling style.
|
||||
@@ -329,7 +301,7 @@ export const myField: Field = {
|
||||
|
||||
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
|
||||
|
||||
Custom Error Components receive all [Field Component](#the-field-component) props, plus the following props:
|
||||
All Error Components receive the following props:
|
||||
|
||||
| Property | Description |
|
||||
| --------------- | ------------------------------------------------------------- |
|
||||
@@ -340,36 +312,6 @@ Custom Error Components receive all [Field Component](#the-field-component) prop
|
||||
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
|
||||
</Banner>
|
||||
|
||||
#### TypeScript
|
||||
|
||||
When building Custom Error Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Error Component, one for every [Field Type](../fields/overview). The convention is to append `ErrorComponent` to the type of field, i.e. `TextFieldErrorComponent`.
|
||||
|
||||
```tsx
|
||||
import type {
|
||||
ArrayFieldErrorComponent,
|
||||
BlocksFieldErrorComponent,
|
||||
CheckboxFieldErrorComponent,
|
||||
CodeFieldErrorComponent,
|
||||
CollapsibleFieldErrorComponent,
|
||||
DateFieldErrorComponent,
|
||||
EmailFieldErrorComponent,
|
||||
GroupFieldErrorComponent,
|
||||
HiddenFieldErrorComponent,
|
||||
JSONFieldErrorComponent,
|
||||
NumberFieldErrorComponent,
|
||||
PointFieldErrorComponent,
|
||||
RadioFieldErrorComponent,
|
||||
RelationshipFieldErrorComponent,
|
||||
RichTextFieldErrorComponent,
|
||||
RowFieldErrorComponent,
|
||||
SelectFieldErrorComponent,
|
||||
TabsFieldErrorComponent,
|
||||
TextFieldErrorComponent,
|
||||
TextareaFieldErrorComponent,
|
||||
UploadFieldErrorComponent
|
||||
} from 'payload'
|
||||
```
|
||||
|
||||
### The Description Property
|
||||
|
||||
Field Descriptions are used to provide additional information to the editor about a field, such as special instructions. Their placement varies from field to field, but typically are displayed with subtle style differences beneath the field inputs.
|
||||
@@ -464,7 +406,7 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
|
||||
|
||||
_For details on how to build a Custom Description, see [Building Custom Components](./components#building-custom-components)._
|
||||
|
||||
Custom Description Components receive all [Field Component](#the-field-component) props, plus the following props:
|
||||
All Description Components receive the following props:
|
||||
|
||||
| Property | Description |
|
||||
| -------------- | ---------------------------------------------------------------- |
|
||||
@@ -475,36 +417,6 @@ Custom Description Components receive all [Field Component](#the-field-component
|
||||
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
|
||||
</Banner>
|
||||
|
||||
#### TypeScript
|
||||
|
||||
When building Custom Description Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Description Component, one for every [Field Type](../fields/overview). The convention is to append `DescriptionComponent` to the type of field, i.e. `TextFieldDescriptionComponent`.
|
||||
|
||||
```tsx
|
||||
import type {
|
||||
ArrayFieldDescriptionComponent,
|
||||
BlocksFieldDescriptionComponent,
|
||||
CheckboxFieldDescriptionComponent,
|
||||
CodeFieldDescriptionComponent,
|
||||
CollapsibleFieldDescriptionComponent,
|
||||
DateFieldDescriptionComponent,
|
||||
EmailFieldDescriptionComponent,
|
||||
GroupFieldDescriptionComponent,
|
||||
HiddenFieldDescriptionComponent,
|
||||
JSONFieldDescriptionComponent,
|
||||
NumberFieldDescriptionComponent,
|
||||
PointFieldDescriptionComponent,
|
||||
RadioFieldDescriptionComponent,
|
||||
RelationshipFieldDescriptionComponent,
|
||||
RichTextFieldDescriptionComponent,
|
||||
RowFieldDescriptionComponent,
|
||||
SelectFieldDescriptionComponent,
|
||||
TabsFieldDescriptionComponent,
|
||||
TextFieldDescriptionComponent,
|
||||
TextareaFieldDescriptionComponent,
|
||||
UploadFieldDescriptionComponent
|
||||
} from 'payload'
|
||||
```
|
||||
|
||||
### afterInput and beforeInput
|
||||
|
||||
With these properties you can add multiple components _before_ and _after_ the input element, as their name suggests. This is useful when you need to render additional elements alongside the field without replacing the entire field component.
|
||||
|
||||
@@ -205,9 +205,7 @@ export const MyField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
Default values can be defined as a static value or a function that returns a value. When a `defaultValue` is defined statically, Payload's DB adapters will apply it to the database schema or models.
|
||||
|
||||
Functions can be written to make use of the following argument properties:
|
||||
Default values can be defined as a static string or a function that returns a string. Functions are called with the following arguments:
|
||||
|
||||
- `user` - the authenticated user object
|
||||
- `locale` - the currently selected locale string
|
||||
@@ -296,7 +294,7 @@ When using custom validation functions, Payload will use yours in place of the d
|
||||
To reuse default field validations, call them from within your custom validation function:
|
||||
|
||||
```ts
|
||||
import { text } from 'payload/shared'
|
||||
import { text } from 'payload/fields/validations'
|
||||
|
||||
const field: Field = {
|
||||
name: 'notBad',
|
||||
|
||||
@@ -193,7 +193,7 @@ You can learn more about writing queries [here](/docs/queries/overview).
|
||||
When a relationship field has both <strong>filterOptions</strong> and a custom{' '}
|
||||
<strong>validate</strong> function, the api will not validate <strong>filterOptions</strong>{' '}
|
||||
unless you call the default relationship field validation function imported from{' '}
|
||||
<strong>payload/shared</strong> in your validate function.
|
||||
<strong>payload/fields/validations</strong> in your validate function.
|
||||
</Banner>
|
||||
|
||||
## How the data is saved
|
||||
|
||||
@@ -57,7 +57,6 @@ export const MyUploadField: Field = {
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`displayPreview`** | Enable displaying preview of the uploaded file. Overrides related Collection's `displayPreview` option. [More](/docs/upload/overview#collection-upload-options). |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [Admin Options](../admin/fields#admin-options). |
|
||||
@@ -124,5 +123,5 @@ You can learn more about writing queries [here](/docs/queries/overview).
|
||||
When an upload field has both <strong>filterOptions</strong> and a custom{' '}
|
||||
<strong>validate</strong> function, the api will not validate <strong>filterOptions</strong>{' '}
|
||||
unless you call the default upload field validation function imported from{' '}
|
||||
<strong>payload/shared</strong> in your validate function.
|
||||
<strong>payload/fields/validations</strong> in your validate function.
|
||||
</Banner>
|
||||
|
||||
@@ -335,6 +335,7 @@ import {
|
||||
FieldMap,
|
||||
File,
|
||||
Form,
|
||||
FormFieldBase,
|
||||
FormLoadingOverlayToggle,
|
||||
FormSubmit,
|
||||
GenerateConfirmation,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Building Your Own Plugin
|
||||
label: Build Your Own
|
||||
order: 20
|
||||
order: 50
|
||||
desc: Starting to build your own plugin? Find everything you need and learn best practices with the Payload plugin template.
|
||||
keywords: plugins, template, config, configuration, extensions, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
@@ -159,60 +159,36 @@ export const seed = async (payload: Payload): Promise<void> => {
|
||||
|
||||
```
|
||||
|
||||
## Building a Plugin
|
||||
## Overview of the src folder
|
||||
|
||||
Now that we have our environment setup and dev project ready to go - it's time to build the plugin!
|
||||
|
||||
**index.ts**
|
||||
|
||||
First up, the `src/index.ts` file - this is where the plugin should be imported from. It is best practice not to build the plugin directly in this file, instead we use this to export the plugin and types from their respective files.
|
||||
|
||||
**Plugin.ts**
|
||||
|
||||
To reiterate, the essence of a [Payload Plugin](./overview) is simply to extend the [Payload Config](../configuration/overview) - and that is exactly what we are doing in this file.
|
||||
|
||||
```
|
||||
import type { Config } from 'payload'
|
||||
|
||||
export const samplePlugin =
|
||||
(pluginOptions: PluginTypes) =>
|
||||
(incomingConfig: Config): Config => {
|
||||
// create copy of incoming config
|
||||
let config = { ...incomingConfig }
|
||||
|
||||
/**
|
||||
* This is where you could modify the
|
||||
* config based on the plugin options
|
||||
*/
|
||||
// do something cool with the config here
|
||||
|
||||
// If you wanted to add a new collection:
|
||||
config.collections = [
|
||||
...(config.collections || []),
|
||||
newCollection,
|
||||
]
|
||||
|
||||
// If you wanted to add a new global:
|
||||
config.globals = [
|
||||
...(config.globals || []),
|
||||
newGlobal,
|
||||
]
|
||||
|
||||
/**
|
||||
* If you wanted to add a new field to a collection:
|
||||
*
|
||||
* 1. Loop over collections
|
||||
* 2. Find the collection you want to add the field to
|
||||
* 3. Add the field to the collection
|
||||
*/
|
||||
|
||||
// If you wanted to add to the onInit:
|
||||
config.onInit = async payload => {
|
||||
if (incomingConfig.onInit) await incomingConfig.onInit(payload)
|
||||
// Add additional onInit code here
|
||||
}
|
||||
|
||||
// Finally, return the modified config
|
||||
return config
|
||||
}
|
||||
```
|
||||
|
||||
To reiterate, the essence of a [Payload Plugin](./overview) is simply to extend the [Payload Config](../configuration/overview) - and that is exactly what we are doing in this file.
|
||||
1. First, you need to receive the existing Payload Config along with any plugin options.
|
||||
2. Then set the variable `config` to be equal to a copy of the existing config.
|
||||
3. From here, you can extend the config however you like!
|
||||
4. Finally, return the config and you're all set.
|
||||
|
||||
|
||||
### Spread syntax
|
||||
## Spread Syntax
|
||||
|
||||
[Spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) (or the spread operator) is a feature in JavaScript that uses the dot notation **(...)** to spread elements from arrays, strings, or objects into various contexts.
|
||||
|
||||
@@ -230,7 +206,7 @@ config.collections = [
|
||||
|
||||
First, you need to spread the `config.collections` to ensure that we don't lose the existing collections. Then you can add any additional collections, just as you would in a regular Payload Config.
|
||||
|
||||
This same logic is applied to other array and object like properties such as admin, globals and hooks:
|
||||
This same logic is applied to other properties like admin, globals, hooks:
|
||||
|
||||
```
|
||||
config.globals = [
|
||||
@@ -244,10 +220,7 @@ config.hooks = {
|
||||
}
|
||||
```
|
||||
|
||||
### Extending functions
|
||||
Function properties cannot use spread syntax. The way to extend them is to execute the existing function if it exists and then run your additional functionality.
|
||||
|
||||
Here is an example extending the `onInit` property:
|
||||
Some properties will be slightly different to extend, for instance the `onInit` property:
|
||||
|
||||
```
|
||||
config.onInit = async payload => {
|
||||
@@ -258,6 +231,10 @@ config.onInit = async payload => {
|
||||
}
|
||||
```
|
||||
|
||||
If you wish to add to the `onInit`, you must include the async/await. We don't use spread syntax in this case, instead you must await the existing `onInit` before running additional functionality.
|
||||
|
||||
In the template, we have stubbed out a basic `onInitExtension` file that you can use, if not needed feel free to delete it.
|
||||
|
||||
## Types
|
||||
|
||||
If your plugin has options, you should define and provide types for these options in a separate file which gets exported from the main `index.ts`.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Form Builder Plugin
|
||||
label: Form Builder
|
||||
order: 40
|
||||
order: 20
|
||||
desc: Easily build and manage forms from the Admin Panel. Send dynamic, personalized emails and even accept and process payments.
|
||||
keywords: plugins, plugin, form, forms, form builder
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Nested Docs Plugin
|
||||
label: Nested Docs
|
||||
order: 40
|
||||
order: 20
|
||||
desc: Nested documents in a parent, child, and sibling relationship.
|
||||
keywords: plugins, nested, documents, parent, child, sibling, relationship
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Redirects Plugin
|
||||
label: Redirects
|
||||
order: 40
|
||||
order: 20
|
||||
desc: Automatically create redirects for your Payload application
|
||||
keywords: plugins, redirects, redirect, plugin, payload, cms, seo, indexing, search, search engine
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Search Plugin
|
||||
label: Search
|
||||
order: 40
|
||||
order: 20
|
||||
desc: Generates records of your documents that are extremely fast to search on.
|
||||
keywords: plugins, search, search plugin, search engine, search index, search results, search bar, search box, search field, search form, search input
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Sentry Plugin
|
||||
label: Sentry
|
||||
order: 40
|
||||
order: 20
|
||||
desc: Integrate Sentry error tracking into your Payload application
|
||||
keywords: plugins, sentry, error, tracking, monitoring, logging, bug, reporting, performance
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: SEO Plugin
|
||||
label: SEO
|
||||
order: 30
|
||||
order: 20
|
||||
desc: Manage SEO metadata from your Payload admin
|
||||
keywords: plugins, seo, meta, search, engine, ranking, google
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Stripe Plugin
|
||||
label: Stripe
|
||||
order: 40
|
||||
order: 20
|
||||
desc: Easily accept payments with Stripe
|
||||
keywords: plugins, stripe, payments, ecommerce
|
||||
---
|
||||
|
||||
@@ -94,7 +94,6 @@ _An asterisk denotes that an option is required._
|
||||
| **`adminThumbnail`** | Set the way that the [Admin Panel](../admin/overview) will display thumbnails for this Collection. [More](#admin-thumbnails) |
|
||||
| **`crop`** | Set to `false` to disable the cropping tool in the [Admin Panel](../admin/overview). Crop is enabled by default. [More](#crop-and-focal-point-selector) |
|
||||
| **`disableLocalStorage`** | Completely disable uploading files to disk locally. [More](#disabling-local-upload-storage) |
|
||||
| **`displayPreview`** | Enable displaying preview of the uploaded file in Upload fields related to this Collection. Can be locally overridden by `displayPreview` option in Upload field. [More](/docs/fields/upload#config-options). |
|
||||
| **`externalFileHeaderFilter`** | Accepts existing headers and returns the headers after filtering or modifying. |
|
||||
| **`filesRequiredOnCreate`** | Mandate file data on creation, default is true. |
|
||||
| **`focalPoint`** | Set to `false` to disable the focal point selection tool in the [Admin Panel](../admin/overview). The focal point selector is only available when `imageSizes` or `resizeOptions` are defined. [More](#crop-and-focal-point-selector) |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload-monorepo",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -119,7 +119,7 @@
|
||||
"create-payload-app": "workspace:*",
|
||||
"cross-env": "7.0.3",
|
||||
"dotenv": "16.4.5",
|
||||
"drizzle-orm": "0.32.1",
|
||||
"drizzle-orm": "0.29.4",
|
||||
"escape-html": "^1.0.3",
|
||||
"execa": "5.1.1",
|
||||
"form-data": "3.0.1",
|
||||
@@ -150,7 +150,7 @@
|
||||
"tempy": "1.0.1",
|
||||
"tsx": "4.16.2",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "5.5.4"
|
||||
"typescript": "5.5.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.0.0 || ^19.0.0-rc-6230622a1a-20240610",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-payload-app",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -50,7 +50,6 @@
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^0.7.0",
|
||||
"@sindresorhus/slugify": "^1.1.0",
|
||||
"@swc/core": "^1.6.13",
|
||||
"arg": "^5.0.0",
|
||||
"chalk": "^4.1.0",
|
||||
"comment-json": "^4.2.3",
|
||||
|
||||
@@ -79,7 +79,7 @@ export async function initNext(args: InitNextArgs): Promise<InitNextResult> {
|
||||
const installSpinner = p.spinner()
|
||||
installSpinner.start('Installing Payload and dependencies...')
|
||||
|
||||
const configurationResult = await installAndConfigurePayload({
|
||||
const configurationResult = installAndConfigurePayload({
|
||||
...args,
|
||||
nextAppDetails,
|
||||
nextConfigType,
|
||||
@@ -143,16 +143,15 @@ async function addPayloadConfigToTsConfig(projectDir: string, isSrcDir: boolean)
|
||||
}
|
||||
}
|
||||
|
||||
async function installAndConfigurePayload(
|
||||
function installAndConfigurePayload(
|
||||
args: {
|
||||
nextAppDetails: NextAppDetails
|
||||
nextConfigType: NextConfigType
|
||||
useDistFiles?: boolean
|
||||
} & InitNextArgs,
|
||||
): Promise<
|
||||
):
|
||||
| { payloadConfigPath: string; success: true }
|
||||
| { payloadConfigPath?: string; reason: string; success: false }
|
||||
> {
|
||||
| { payloadConfigPath?: string; reason: string; success: false } {
|
||||
const {
|
||||
'--debug': debug,
|
||||
nextAppDetails: { isSrcDir, nextAppDir, nextConfigPath } = {},
|
||||
@@ -213,7 +212,7 @@ async function installAndConfigurePayload(
|
||||
copyRecursiveSync(templateSrcDir, path.dirname(nextConfigPath), debug)
|
||||
|
||||
// Wrap next.config.js with withPayload
|
||||
await wrapNextConfig({ nextConfigPath, nextConfigType })
|
||||
wrapNextConfig({ nextConfigPath, nextConfigType })
|
||||
|
||||
return {
|
||||
payloadConfigPath: path.resolve(nextAppDir, '../payload.config.ts'),
|
||||
@@ -240,63 +239,25 @@ async function installDeps(projectDir: string, packageManager: PackageManager, d
|
||||
export async function getNextAppDetails(projectDir: string): Promise<NextAppDetails> {
|
||||
const isSrcDir = fs.existsSync(path.resolve(projectDir, 'src'))
|
||||
|
||||
// Match next.config.js, next.config.ts, next.config.mjs, next.config.cjs
|
||||
const nextConfigPath: string | undefined = (
|
||||
await globby('next.config.(\\w)?(t|j)s', { absolute: true, cwd: projectDir })
|
||||
await globby('next.config.*js', { absolute: true, cwd: projectDir })
|
||||
)?.[0]
|
||||
|
||||
if (!nextConfigPath || nextConfigPath.length === 0) {
|
||||
return {
|
||||
hasTopLevelLayout: false,
|
||||
isSrcDir,
|
||||
isSupportedNextVersion: false,
|
||||
nextConfigPath: undefined,
|
||||
nextVersion: null,
|
||||
}
|
||||
}
|
||||
|
||||
const packageObj = await fse.readJson(path.resolve(projectDir, 'package.json'))
|
||||
// Check if Next.js version is new enough
|
||||
let nextVersion = null
|
||||
if (packageObj.dependencies?.next) {
|
||||
nextVersion = packageObj.dependencies.next
|
||||
// Match versions using regex matching groups
|
||||
const versionMatch = /(?<major>\d+)/.exec(nextVersion)
|
||||
if (!versionMatch) {
|
||||
p.log.warn(`Could not determine Next.js version from ${nextVersion}`)
|
||||
return {
|
||||
hasTopLevelLayout: false,
|
||||
isSrcDir,
|
||||
isSupportedNextVersion: false,
|
||||
nextConfigPath,
|
||||
nextVersion,
|
||||
}
|
||||
}
|
||||
|
||||
const { major } = versionMatch.groups as { major: string }
|
||||
const majorVersion = parseInt(major)
|
||||
if (majorVersion < 15) {
|
||||
return {
|
||||
hasTopLevelLayout: false,
|
||||
isSrcDir,
|
||||
isSupportedNextVersion: false,
|
||||
nextConfigPath,
|
||||
nextVersion,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isSupportedNextVersion = true
|
||||
|
||||
// Check if Payload already installed
|
||||
if (packageObj.dependencies?.payload) {
|
||||
return {
|
||||
hasTopLevelLayout: false,
|
||||
isPayloadInstalled: true,
|
||||
isSrcDir,
|
||||
isSupportedNextVersion,
|
||||
nextConfigPath,
|
||||
nextVersion,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,27 +280,14 @@ export async function getNextAppDetails(projectDir: string): Promise<NextAppDeta
|
||||
? fs.existsSync(path.resolve(nextAppDir, 'layout.tsx'))
|
||||
: false
|
||||
|
||||
return {
|
||||
hasTopLevelLayout,
|
||||
isSrcDir,
|
||||
isSupportedNextVersion,
|
||||
nextAppDir,
|
||||
nextConfigPath,
|
||||
nextConfigType: configType,
|
||||
nextVersion,
|
||||
}
|
||||
return { hasTopLevelLayout, isSrcDir, nextAppDir, nextConfigPath, nextConfigType: configType }
|
||||
}
|
||||
|
||||
function getProjectType(args: {
|
||||
nextConfigPath: string
|
||||
packageObj: Record<string, unknown>
|
||||
}): NextConfigType {
|
||||
}): 'cjs' | 'esm' {
|
||||
const { nextConfigPath, packageObj } = args
|
||||
|
||||
if (nextConfigPath.endsWith('.ts')) {
|
||||
return 'ts'
|
||||
}
|
||||
|
||||
if (nextConfigPath.endsWith('.mjs')) {
|
||||
return 'esm'
|
||||
}
|
||||
|
||||
@@ -29,22 +29,9 @@ const postgresReplacement: DbAdapterReplacement = {
|
||||
packageName: '@payloadcms/db-postgres',
|
||||
}
|
||||
|
||||
const sqliteReplacement: DbAdapterReplacement = {
|
||||
configReplacement: (envName = 'DATABASE_URI') => [
|
||||
' db: sqliteAdapter({',
|
||||
' client: {',
|
||||
` url: process.env.${envName} || '',`,
|
||||
' },',
|
||||
' }),',
|
||||
],
|
||||
importReplacement: "import { sqliteAdapter } from '@payloadcms/db-sqlite'",
|
||||
packageName: '@payloadcms/db-sqlite',
|
||||
}
|
||||
|
||||
export const dbReplacements: Record<DbType, DbAdapterReplacement> = {
|
||||
mongodb: mongodbReplacement,
|
||||
postgres: postgresReplacement,
|
||||
sqlite: sqliteReplacement,
|
||||
}
|
||||
|
||||
type StorageAdapterReplacement = {
|
||||
|
||||
@@ -5,7 +5,6 @@ import type { CliArgs, DbDetails, DbType } from '../types.js'
|
||||
|
||||
type DbChoice = {
|
||||
dbConnectionPrefix: `${string}/`
|
||||
dbConnectionSuffix?: string
|
||||
title: string
|
||||
value: DbType
|
||||
}
|
||||
@@ -21,12 +20,6 @@ const dbChoiceRecord: Record<DbType, DbChoice> = {
|
||||
title: 'PostgreSQL (beta)',
|
||||
value: 'postgres',
|
||||
},
|
||||
sqlite: {
|
||||
dbConnectionPrefix: 'file:./',
|
||||
dbConnectionSuffix: '.db',
|
||||
title: 'SQLite (beta)',
|
||||
value: 'sqlite',
|
||||
},
|
||||
}
|
||||
|
||||
export async function selectDb(args: CliArgs, projectName: string): Promise<DbDetails> {
|
||||
@@ -44,10 +37,10 @@ export async function selectDb(args: CliArgs, projectName: string): Promise<DbDe
|
||||
dbType = await p.select<{ label: string; value: DbType }[], DbType>({
|
||||
initialValue: 'mongodb',
|
||||
message: `Select a database`,
|
||||
options: Object.values(dbChoiceRecord).map((dbChoice) => ({
|
||||
label: dbChoice.title,
|
||||
value: dbChoice.value,
|
||||
})),
|
||||
options: [
|
||||
{ label: 'MongoDB', value: 'mongodb' },
|
||||
{ label: 'Postgres', value: 'postgres' },
|
||||
],
|
||||
})
|
||||
if (p.isCancel(dbType)) process.exit(0)
|
||||
}
|
||||
@@ -57,7 +50,7 @@ export async function selectDb(args: CliArgs, projectName: string): Promise<DbDe
|
||||
let dbUri: string | symbol | undefined = undefined
|
||||
const initialDbUri = `${dbChoice.dbConnectionPrefix}${
|
||||
projectName === '.' ? `payload-${getRandomDigitSuffix()}` : slugify(projectName)
|
||||
}${dbChoice.dbConnectionSuffix || ''}`
|
||||
}`
|
||||
|
||||
if (args['--db-accept-recommended']) {
|
||||
dbUri = initialDbUri
|
||||
|
||||
@@ -74,11 +74,9 @@ export async function updatePayloadInProject(
|
||||
info('Payload packages updated successfully.')
|
||||
|
||||
info(`Updating Payload Next.js files...`)
|
||||
|
||||
const templateFilesPath =
|
||||
process.env.JEST_WORKER_ID !== undefined
|
||||
? path.resolve(dirname, '../../../../templates/blank-3.0')
|
||||
: path.resolve(dirname, '../..', 'dist/template')
|
||||
const templateFilesPath = dirname.endsWith('dist')
|
||||
? path.resolve(dirname, '../..', 'dist/template')
|
||||
: path.resolve(dirname, '../../../../templates/blank-3.0')
|
||||
|
||||
const templateSrcDir = path.resolve(templateFilesPath, 'src/app/(payload)')
|
||||
|
||||
|
||||
@@ -3,35 +3,6 @@ import { jest } from '@jest/globals'
|
||||
|
||||
import { parseAndModifyConfigContent, withPayloadStatement } from './wrap-next-config.js'
|
||||
|
||||
const tsConfigs = {
|
||||
defaultNextConfig: `import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {};
|
||||
export default nextConfig;`,
|
||||
|
||||
nextConfigExportNamedDefault: `import type { NextConfig } from "next";
|
||||
const nextConfig: NextConfig = {};
|
||||
const wrapped = someFunc(asdf);
|
||||
export { wrapped as default };
|
||||
`,
|
||||
nextConfigWithFunc: `import type { NextConfig } from "next";
|
||||
const nextConfig: NextConfig = {};
|
||||
export default someFunc(nextConfig);
|
||||
`,
|
||||
nextConfigWithFuncMultiline: `import type { NextConfig } from "next";
|
||||
const nextConfig: NextConfig = {};
|
||||
export default someFunc(
|
||||
nextConfig
|
||||
);
|
||||
`,
|
||||
nextConfigWithSpread: `import type { NextConfig } from "next";
|
||||
const nextConfig: NextConfig = {
|
||||
...someConfig,
|
||||
};
|
||||
export default nextConfig;
|
||||
`,
|
||||
}
|
||||
|
||||
const esmConfigs = {
|
||||
defaultNextConfig: `/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
@@ -81,66 +52,27 @@ module.exports = nextConfig;
|
||||
}
|
||||
|
||||
describe('parseAndInsertWithPayload', () => {
|
||||
describe('ts', () => {
|
||||
const configType = 'ts'
|
||||
const importStatement = withPayloadStatement[configType]
|
||||
|
||||
it('should parse the default next config', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
tsConfigs.defaultNextConfig,
|
||||
configType,
|
||||
)
|
||||
expect(modifiedConfigContent).toContain(importStatement)
|
||||
expect(modifiedConfigContent).toContain('withPayload(nextConfig)')
|
||||
})
|
||||
|
||||
it('should parse the config with a function', async () => {
|
||||
const { modifiedConfigContent: modifiedConfigContent2 } = await parseAndModifyConfigContent(
|
||||
tsConfigs.nextConfigWithFunc,
|
||||
configType,
|
||||
)
|
||||
expect(modifiedConfigContent2).toContain('withPayload(someFunc(nextConfig))')
|
||||
})
|
||||
|
||||
it('should parse the config with a multi-lined function', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
tsConfigs.nextConfigWithFuncMultiline,
|
||||
configType,
|
||||
)
|
||||
expect(modifiedConfigContent).toContain(importStatement)
|
||||
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/)
|
||||
})
|
||||
|
||||
it('should parse the config with a spread', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
tsConfigs.nextConfigWithSpread,
|
||||
configType,
|
||||
)
|
||||
expect(modifiedConfigContent).toContain(importStatement)
|
||||
expect(modifiedConfigContent).toContain('withPayload(nextConfig)')
|
||||
})
|
||||
})
|
||||
describe('esm', () => {
|
||||
const configType = 'esm'
|
||||
const importStatement = withPayloadStatement[configType]
|
||||
it('should parse the default next config', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
it('should parse the default next config', () => {
|
||||
const { modifiedConfigContent } = parseAndModifyConfigContent(
|
||||
esmConfigs.defaultNextConfig,
|
||||
configType,
|
||||
)
|
||||
expect(modifiedConfigContent).toContain(importStatement)
|
||||
expect(modifiedConfigContent).toContain('withPayload(nextConfig)')
|
||||
})
|
||||
it('should parse the config with a function', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
it('should parse the config with a function', () => {
|
||||
const { modifiedConfigContent } = parseAndModifyConfigContent(
|
||||
esmConfigs.nextConfigWithFunc,
|
||||
configType,
|
||||
)
|
||||
expect(modifiedConfigContent).toContain('withPayload(someFunc(nextConfig))')
|
||||
})
|
||||
|
||||
it('should parse the config with a multi-lined function', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
it('should parse the config with a function on a new line', () => {
|
||||
const { modifiedConfigContent } = parseAndModifyConfigContent(
|
||||
esmConfigs.nextConfigWithFuncMultiline,
|
||||
configType,
|
||||
)
|
||||
@@ -148,8 +80,8 @@ describe('parseAndInsertWithPayload', () => {
|
||||
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/)
|
||||
})
|
||||
|
||||
it('should parse the config with a spread', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
it('should parse the config with a spread', () => {
|
||||
const { modifiedConfigContent } = parseAndModifyConfigContent(
|
||||
esmConfigs.nextConfigWithSpread,
|
||||
configType,
|
||||
)
|
||||
@@ -158,10 +90,10 @@ describe('parseAndInsertWithPayload', () => {
|
||||
})
|
||||
|
||||
// Unsupported: export { wrapped as default }
|
||||
it('should give warning with a named export as default', async () => {
|
||||
it('should give warning with a named export as default', () => {
|
||||
const warnLogSpy = jest.spyOn(p.log, 'warn').mockImplementation(() => {})
|
||||
|
||||
const { modifiedConfigContent, success } = await parseAndModifyConfigContent(
|
||||
const { modifiedConfigContent, success } = parseAndModifyConfigContent(
|
||||
esmConfigs.nextConfigExportNamedDefault,
|
||||
configType,
|
||||
)
|
||||
@@ -177,39 +109,39 @@ describe('parseAndInsertWithPayload', () => {
|
||||
describe('cjs', () => {
|
||||
const configType = 'cjs'
|
||||
const requireStatement = withPayloadStatement[configType]
|
||||
it('should parse the default next config', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
it('should parse the default next config', () => {
|
||||
const { modifiedConfigContent } = parseAndModifyConfigContent(
|
||||
cjsConfigs.defaultNextConfig,
|
||||
configType,
|
||||
)
|
||||
expect(modifiedConfigContent).toContain(requireStatement)
|
||||
expect(modifiedConfigContent).toContain('withPayload(nextConfig)')
|
||||
})
|
||||
it('should parse anonymous default config', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
it('should parse anonymous default config', () => {
|
||||
const { modifiedConfigContent } = parseAndModifyConfigContent(
|
||||
cjsConfigs.anonConfig,
|
||||
configType,
|
||||
)
|
||||
expect(modifiedConfigContent).toContain(requireStatement)
|
||||
expect(modifiedConfigContent).toContain('withPayload({})')
|
||||
})
|
||||
it('should parse the config with a function', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
it('should parse the config with a function', () => {
|
||||
const { modifiedConfigContent } = parseAndModifyConfigContent(
|
||||
cjsConfigs.nextConfigWithFunc,
|
||||
configType,
|
||||
)
|
||||
expect(modifiedConfigContent).toContain('withPayload(someFunc(nextConfig))')
|
||||
})
|
||||
it('should parse the config with a multi-lined function', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
it('should parse the config with a function on a new line', () => {
|
||||
const { modifiedConfigContent } = parseAndModifyConfigContent(
|
||||
cjsConfigs.nextConfigWithFuncMultiline,
|
||||
configType,
|
||||
)
|
||||
expect(modifiedConfigContent).toContain(requireStatement)
|
||||
expect(modifiedConfigContent).toMatch(/withPayload\(someFunc\(\n {2}nextConfig\n\)\)/)
|
||||
})
|
||||
it('should parse the config with a named export as default', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
it('should parse the config with a named export as default', () => {
|
||||
const { modifiedConfigContent } = parseAndModifyConfigContent(
|
||||
cjsConfigs.nextConfigExportNamedDefault,
|
||||
configType,
|
||||
)
|
||||
@@ -217,8 +149,8 @@ describe('parseAndInsertWithPayload', () => {
|
||||
expect(modifiedConfigContent).toContain('withPayload(wrapped)')
|
||||
})
|
||||
|
||||
it('should parse the config with a spread', async () => {
|
||||
const { modifiedConfigContent } = await parseAndModifyConfigContent(
|
||||
it('should parse the config with a spread', () => {
|
||||
const { modifiedConfigContent } = parseAndModifyConfigContent(
|
||||
cjsConfigs.nextConfigWithSpread,
|
||||
configType,
|
||||
)
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
import type { ExportDefaultExpression, ModuleItem } from '@swc/core'
|
||||
import type { Program } from 'esprima-next'
|
||||
|
||||
import swc from '@swc/core'
|
||||
import chalk from 'chalk'
|
||||
import { Syntax, parseModule } from 'esprima-next'
|
||||
import fs from 'fs'
|
||||
|
||||
import type { NextConfigType } from '../types.js'
|
||||
|
||||
import { log, warning } from '../utils/log.js'
|
||||
|
||||
export const withPayloadStatement = {
|
||||
cjs: `const { withPayload } = require("@payloadcms/next/withPayload");`,
|
||||
esm: `import { withPayload } from "@payloadcms/next/withPayload";`,
|
||||
ts: `import { withPayload } from "@payloadcms/next/withPayload";`,
|
||||
cjs: `const { withPayload } = require('@payloadcms/next/withPayload')\n`,
|
||||
esm: `import { withPayload } from '@payloadcms/next/withPayload'\n`,
|
||||
}
|
||||
|
||||
export const wrapNextConfig = async (args: {
|
||||
type NextConfigType = 'cjs' | 'esm'
|
||||
|
||||
export const wrapNextConfig = (args: {
|
||||
nextConfigPath: string
|
||||
nextConfigType: NextConfigType
|
||||
}) => {
|
||||
const { nextConfigPath, nextConfigType: configType } = args
|
||||
const configContent = fs.readFileSync(nextConfigPath, 'utf8')
|
||||
const { modifiedConfigContent: newConfig, success } = await parseAndModifyConfigContent(
|
||||
const { modifiedConfigContent: newConfig, success } = parseAndModifyConfigContent(
|
||||
configContent,
|
||||
configType,
|
||||
)
|
||||
@@ -36,142 +34,113 @@ export const wrapNextConfig = async (args: {
|
||||
/**
|
||||
* Parses config content with AST and wraps it with withPayload function
|
||||
*/
|
||||
export async function parseAndModifyConfigContent(
|
||||
export function parseAndModifyConfigContent(
|
||||
content: string,
|
||||
configType: NextConfigType,
|
||||
): Promise<{ modifiedConfigContent: string; success: boolean }> {
|
||||
content = withPayloadStatement[configType] + '\n' + content
|
||||
): { modifiedConfigContent: string; success: boolean } {
|
||||
content = withPayloadStatement[configType] + content
|
||||
|
||||
console.log({ configType, content })
|
||||
|
||||
if (configType === 'cjs' || configType === 'esm') {
|
||||
try {
|
||||
const ast = parseModule(content, { loc: true })
|
||||
|
||||
if (configType === 'cjs') {
|
||||
// Find `module.exports = X`
|
||||
const moduleExports = ast.body.find(
|
||||
(p) =>
|
||||
p.type === Syntax.ExpressionStatement &&
|
||||
p.expression?.type === Syntax.AssignmentExpression &&
|
||||
p.expression.left?.type === Syntax.MemberExpression &&
|
||||
p.expression.left.object?.type === Syntax.Identifier &&
|
||||
p.expression.left.object.name === 'module' &&
|
||||
p.expression.left.property?.type === Syntax.Identifier &&
|
||||
p.expression.left.property.name === 'exports',
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
) as any
|
||||
|
||||
if (moduleExports && moduleExports.expression.right?.loc) {
|
||||
const modifiedConfigContent = insertBeforeAndAfter(
|
||||
content,
|
||||
moduleExports.expression.right.loc,
|
||||
)
|
||||
return { modifiedConfigContent, success: true }
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
modifiedConfigContent: content,
|
||||
success: false,
|
||||
})
|
||||
} else if (configType === 'esm') {
|
||||
const exportDefaultDeclaration = ast.body.find(
|
||||
(p) => p.type === Syntax.ExportDefaultDeclaration,
|
||||
) as Directive | undefined
|
||||
|
||||
const exportNamedDeclaration = ast.body.find(
|
||||
(p) => p.type === Syntax.ExportNamedDeclaration,
|
||||
) as ExportNamedDeclaration | undefined
|
||||
|
||||
if (!exportDefaultDeclaration && !exportNamedDeclaration) {
|
||||
throw new Error('Could not find ExportDefaultDeclaration in next.config.js')
|
||||
}
|
||||
|
||||
if (exportDefaultDeclaration && exportDefaultDeclaration.declaration?.loc) {
|
||||
const modifiedConfigContent = insertBeforeAndAfter(
|
||||
content,
|
||||
exportDefaultDeclaration.declaration.loc,
|
||||
)
|
||||
return { modifiedConfigContent, success: true }
|
||||
} else if (exportNamedDeclaration) {
|
||||
const exportSpecifier = exportNamedDeclaration.specifiers.find(
|
||||
(s) =>
|
||||
s.type === 'ExportSpecifier' &&
|
||||
s.exported?.name === 'default' &&
|
||||
s.local?.type === 'Identifier' &&
|
||||
s.local?.name,
|
||||
)
|
||||
|
||||
if (exportSpecifier) {
|
||||
warning('Could not automatically wrap next.config.js with withPayload.')
|
||||
warning('Automatic wrapping of named exports as default not supported yet.')
|
||||
|
||||
warnUserWrapNotSuccessful(configType)
|
||||
return {
|
||||
modifiedConfigContent: content,
|
||||
success: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
warning('Could not automatically wrap Next config with withPayload.')
|
||||
warnUserWrapNotSuccessful(configType)
|
||||
return Promise.resolve({
|
||||
modifiedConfigContent: content,
|
||||
success: false,
|
||||
})
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
warning(`Unable to parse Next config. Error: ${error.message} `)
|
||||
warnUserWrapNotSuccessful(configType)
|
||||
}
|
||||
return {
|
||||
modifiedConfigContent: content,
|
||||
success: false,
|
||||
}
|
||||
let ast: Program | undefined
|
||||
try {
|
||||
ast = parseModule(content, { loc: true })
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Error) {
|
||||
warning(`Unable to parse Next config. Error: ${error.message} `)
|
||||
warnUserWrapNotSuccessful(configType)
|
||||
}
|
||||
} else if (configType === 'ts') {
|
||||
const { moduleItems, parseOffset } = await compileTypeScriptFileToAST(content)
|
||||
return {
|
||||
modifiedConfigContent: content,
|
||||
success: false,
|
||||
}
|
||||
}
|
||||
|
||||
const exportDefaultDeclaration = moduleItems.find(
|
||||
(m) =>
|
||||
m.type === 'ExportDefaultExpression' &&
|
||||
(m.expression.type === 'Identifier' || m.expression.type === 'CallExpression'),
|
||||
) as ExportDefaultExpression | undefined
|
||||
if (configType === 'esm') {
|
||||
const exportDefaultDeclaration = ast.body.find(
|
||||
(p) => p.type === Syntax.ExportDefaultDeclaration,
|
||||
) as Directive | undefined
|
||||
|
||||
if (exportDefaultDeclaration) {
|
||||
if (!('span' in exportDefaultDeclaration.expression)) {
|
||||
warning('Could not automatically wrap Next config with withPayload.')
|
||||
warnUserWrapNotSuccessful(configType)
|
||||
return Promise.resolve({
|
||||
modifiedConfigContent: content,
|
||||
success: false,
|
||||
})
|
||||
}
|
||||
const exportNamedDeclaration = ast.body.find(
|
||||
(p) => p.type === Syntax.ExportNamedDeclaration,
|
||||
) as ExportNamedDeclaration | undefined
|
||||
|
||||
const modifiedConfigContent = insertBeforeAndAfterSWC(
|
||||
if (!exportDefaultDeclaration && !exportNamedDeclaration) {
|
||||
throw new Error('Could not find ExportDefaultDeclaration in next.config.js')
|
||||
}
|
||||
|
||||
if (exportDefaultDeclaration && exportDefaultDeclaration.declaration?.loc) {
|
||||
const modifiedConfigContent = insertBeforeAndAfter(
|
||||
content,
|
||||
exportDefaultDeclaration.expression.span,
|
||||
parseOffset,
|
||||
exportDefaultDeclaration.declaration.loc,
|
||||
)
|
||||
return { modifiedConfigContent, success: true }
|
||||
} else if (exportNamedDeclaration) {
|
||||
const exportSpecifier = exportNamedDeclaration.specifiers.find(
|
||||
(s) =>
|
||||
s.type === 'ExportSpecifier' &&
|
||||
s.exported?.name === 'default' &&
|
||||
s.local?.type === 'Identifier' &&
|
||||
s.local?.name,
|
||||
)
|
||||
|
||||
if (exportSpecifier) {
|
||||
warning('Could not automatically wrap next.config.js with withPayload.')
|
||||
warning('Automatic wrapping of named exports as default not supported yet.')
|
||||
|
||||
warnUserWrapNotSuccessful(configType)
|
||||
return {
|
||||
modifiedConfigContent: content,
|
||||
success: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
warning('Could not automatically wrap Next config with withPayload.')
|
||||
warnUserWrapNotSuccessful(configType)
|
||||
return {
|
||||
modifiedConfigContent: content,
|
||||
success: false,
|
||||
}
|
||||
} else if (configType === 'cjs') {
|
||||
// Find `module.exports = X`
|
||||
const moduleExports = ast.body.find(
|
||||
(p) =>
|
||||
p.type === Syntax.ExpressionStatement &&
|
||||
p.expression?.type === Syntax.AssignmentExpression &&
|
||||
p.expression.left?.type === Syntax.MemberExpression &&
|
||||
p.expression.left.object?.type === Syntax.Identifier &&
|
||||
p.expression.left.object.name === 'module' &&
|
||||
p.expression.left.property?.type === Syntax.Identifier &&
|
||||
p.expression.left.property.name === 'exports',
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
) as any
|
||||
|
||||
if (moduleExports && moduleExports.expression.right?.loc) {
|
||||
const modifiedConfigContent = insertBeforeAndAfter(
|
||||
content,
|
||||
moduleExports.expression.right.loc,
|
||||
)
|
||||
return { modifiedConfigContent, success: true }
|
||||
}
|
||||
|
||||
return {
|
||||
modifiedConfigContent: content,
|
||||
success: false,
|
||||
}
|
||||
}
|
||||
|
||||
warning('Could not automatically wrap Next config with withPayload.')
|
||||
warnUserWrapNotSuccessful(configType)
|
||||
return Promise.resolve({
|
||||
return {
|
||||
modifiedConfigContent: content,
|
||||
success: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function warnUserWrapNotSuccessful(configType: NextConfigType) {
|
||||
// Output directions for user to update next.config.js
|
||||
const withPayloadMessage = `
|
||||
|
||||
${chalk.bold(`Please manually wrap your existing Next config with the withPayload function. Here is an example:`)}
|
||||
${chalk.bold(`Please manually wrap your existing next.config.js with the withPayload function. Here is an example:`)}
|
||||
|
||||
${withPayloadStatement[configType]}
|
||||
|
||||
@@ -179,7 +148,7 @@ function warnUserWrapNotSuccessful(configType: NextConfigType) {
|
||||
// Your Next.js config here
|
||||
}
|
||||
|
||||
${configType === 'cjs' ? 'module.exports = withPayload(nextConfig)' : 'export default withPayload(nextConfig)'}
|
||||
${configType === 'esm' ? 'export default withPayload(nextConfig)' : 'module.exports = withPayload(nextConfig)'}
|
||||
|
||||
`
|
||||
|
||||
@@ -217,7 +186,7 @@ type Loc = {
|
||||
start: { column: number; line: number }
|
||||
}
|
||||
|
||||
function insertBeforeAndAfter(content: string, loc: Loc): string {
|
||||
function insertBeforeAndAfter(content: string, loc: Loc) {
|
||||
const { end, start } = loc
|
||||
const lines = content.split('\n')
|
||||
|
||||
@@ -236,57 +205,3 @@ function insertBeforeAndAfter(content: string, loc: Loc): string {
|
||||
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
function insertBeforeAndAfterSWC(
|
||||
content: string,
|
||||
span: ModuleItem['span'],
|
||||
/**
|
||||
* WARNING: This is ONLY for unit tests. Defaults to 0 otherwise.
|
||||
*
|
||||
* @see compileTypeScriptFileToAST
|
||||
*/
|
||||
parseOffset: number,
|
||||
): string {
|
||||
const { end: preOffsetEnd, start: preOffsetStart } = span
|
||||
|
||||
const start = preOffsetStart - parseOffset
|
||||
const end = preOffsetEnd - parseOffset
|
||||
|
||||
const insert = (pos: number, text: string): string => {
|
||||
return content.slice(0, pos) + text + content.slice(pos)
|
||||
}
|
||||
|
||||
// insert ) after end
|
||||
content = insert(end - 1, ')')
|
||||
// insert withPayload before start
|
||||
content = insert(start - 1, 'withPayload(')
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile typescript to AST using the swc compiler
|
||||
*/
|
||||
async function compileTypeScriptFileToAST(
|
||||
fileContent: string,
|
||||
): Promise<{ moduleItems: ModuleItem[]; parseOffset: number }> {
|
||||
let parseOffset = 0
|
||||
|
||||
/**
|
||||
* WARNING: This is ONLY for unit tests.
|
||||
*
|
||||
* Multiple instances of swc DO NOT reset the .span.end value.
|
||||
* During unit tests, the .spawn.end value is read and accounted for.
|
||||
*
|
||||
* https://github.com/swc-project/swc/issues/1366
|
||||
*/
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
parseOffset = (await swc.parse('')).span.end
|
||||
}
|
||||
|
||||
const module = await swc.parse(fileContent, {
|
||||
syntax: 'typescript',
|
||||
})
|
||||
|
||||
return { moduleItems: module.body, parseOffset }
|
||||
}
|
||||
|
||||
@@ -85,22 +85,7 @@ export class Main {
|
||||
|
||||
// Detect if inside Next.js project
|
||||
const nextAppDetails = await getNextAppDetails(process.cwd())
|
||||
const {
|
||||
hasTopLevelLayout,
|
||||
isPayloadInstalled,
|
||||
isSupportedNextVersion,
|
||||
nextAppDir,
|
||||
nextConfigPath,
|
||||
nextVersion,
|
||||
} = nextAppDetails
|
||||
|
||||
if (nextConfigPath && !isSupportedNextVersion) {
|
||||
p.log.warn(
|
||||
`Next.js v${nextVersion} is unsupported. Next.js >= 15 is required to use Payload.`,
|
||||
)
|
||||
p.outro(feedbackOutro())
|
||||
process.exit(0)
|
||||
}
|
||||
const { hasTopLevelLayout, isPayloadInstalled, nextAppDir, nextConfigPath } = nextAppDetails
|
||||
|
||||
// Upgrade Payload in existing project
|
||||
if (isPayloadInstalled && nextConfigPath) {
|
||||
|
||||
@@ -57,7 +57,7 @@ interface Template {
|
||||
|
||||
export type PackageManager = 'bun' | 'npm' | 'pnpm' | 'yarn'
|
||||
|
||||
export type DbType = 'mongodb' | 'postgres' | 'sqlite'
|
||||
export type DbType = 'mongodb' | 'postgres'
|
||||
|
||||
export type DbDetails = {
|
||||
dbUri: string
|
||||
@@ -70,13 +70,11 @@ export type NextAppDetails = {
|
||||
hasTopLevelLayout: boolean
|
||||
isPayloadInstalled?: boolean
|
||||
isSrcDir: boolean
|
||||
isSupportedNextVersion: boolean
|
||||
nextAppDir?: string
|
||||
nextConfigPath?: string
|
||||
nextConfigType?: NextConfigType
|
||||
nextVersion: null | string
|
||||
}
|
||||
|
||||
export type NextConfigType = 'cjs' | 'esm' | 'ts'
|
||||
export type NextConfigType = 'cjs' | 'esm'
|
||||
|
||||
export type StorageAdapterType = 'localDisk' | 'payloadCloud' | 'vercelBlobStorage'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-mongodb",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"description": "The officially supported MongoDB database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -64,7 +64,7 @@ export const findGlobalVersions: FindGlobalVersions = async function findGlobalV
|
||||
forceCountFn: hasNearConstraint,
|
||||
lean: true,
|
||||
leanWithId: true,
|
||||
limit,
|
||||
offset: skip,
|
||||
options,
|
||||
page,
|
||||
pagination,
|
||||
|
||||
@@ -52,19 +52,9 @@ type FieldSchemaGenerator = (
|
||||
buildSchemaOptions: BuildSchemaOptions,
|
||||
) => void
|
||||
|
||||
/**
|
||||
* get a field's defaultValue only if defined and not dynamic so that it can be set on the field schema
|
||||
* @param field
|
||||
*/
|
||||
const formatDefaultValue = (field: FieldAffectingData) =>
|
||||
typeof field.defaultValue !== 'undefined' && typeof field.defaultValue !== 'function'
|
||||
? field.defaultValue
|
||||
: undefined
|
||||
|
||||
const formatBaseSchema = (field: FieldAffectingData, buildSchemaOptions: BuildSchemaOptions) => {
|
||||
const { disableUnique, draftsEnabled, indexSortableFields } = buildSchemaOptions
|
||||
const schema: SchemaTypeOptions<unknown> = {
|
||||
default: formatDefaultValue(field),
|
||||
index: field.index || (!disableUnique && field.unique) || indexSortableFields || false,
|
||||
required: false,
|
||||
unique: (!disableUnique && field.unique) || false,
|
||||
@@ -169,6 +159,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
},
|
||||
}),
|
||||
],
|
||||
default: undefined,
|
||||
}
|
||||
|
||||
schema.add({
|
||||
@@ -183,6 +174,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
): void => {
|
||||
const fieldSchema = {
|
||||
type: [new mongoose.Schema({}, { _id: false, discriminatorKey: 'blockType' })],
|
||||
default: undefined,
|
||||
}
|
||||
|
||||
schema.add({
|
||||
@@ -347,7 +339,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
},
|
||||
coordinates: {
|
||||
type: [Number],
|
||||
default: formatDefaultValue(field),
|
||||
default: field.defaultValue || undefined,
|
||||
required: false,
|
||||
},
|
||||
}
|
||||
@@ -428,9 +420,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
|
||||
return {
|
||||
...locales,
|
||||
[locale]: field.hasMany
|
||||
? { type: [localeSchema], default: formatDefaultValue(field) }
|
||||
: localeSchema,
|
||||
[locale]: field.hasMany ? { type: [localeSchema], default: undefined } : localeSchema,
|
||||
}
|
||||
}, {}),
|
||||
localized: true,
|
||||
@@ -450,7 +440,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
if (field.hasMany) {
|
||||
schemaToReturn = {
|
||||
type: [schemaToReturn],
|
||||
default: formatDefaultValue(field),
|
||||
default: undefined,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -463,7 +453,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
||||
if (field.hasMany) {
|
||||
schemaToReturn = {
|
||||
type: [schemaToReturn],
|
||||
default: formatDefaultValue(field),
|
||||
default: undefined,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
@@ -47,8 +47,8 @@
|
||||
"dependencies": {
|
||||
"@payloadcms/drizzle": "workspace:*",
|
||||
"console-table-printer": "2.11.2",
|
||||
"drizzle-kit": "0.23.2",
|
||||
"drizzle-orm": "0.32.1",
|
||||
"drizzle-kit": "0.20.14-1f2c838",
|
||||
"drizzle-orm": "0.29.4",
|
||||
"pg": "8.11.3",
|
||||
"prompts": "2.4.2",
|
||||
"to-snake-case": "1.0.0",
|
||||
|
||||
@@ -53,7 +53,6 @@ export const connect: Connect = async function connect(
|
||||
const { hotReload } = options
|
||||
|
||||
this.schema = {
|
||||
pgSchema: this.pgSchema,
|
||||
...this.tables,
|
||||
...this.relations,
|
||||
...this.enums,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DrizzleSnapshotJSON } from 'drizzle-kit/api'
|
||||
import type { DrizzleSnapshotJSON } from 'drizzle-kit/payload'
|
||||
import type { CreateMigration } from 'payload'
|
||||
|
||||
import fs from 'fs'
|
||||
@@ -25,7 +25,7 @@ export const createMigration: CreateMigration = async function createMigration(
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir)
|
||||
}
|
||||
const { generateDrizzleJson, generateMigration } = require('drizzle-kit/api')
|
||||
const { generateDrizzleJson, generateMigration } = require('drizzle-kit/payload')
|
||||
const drizzleJsonAfter = generateDrizzleJson(this.schema)
|
||||
const [yyymmdd, hhmmss] = new Date().toISOString().split('T')
|
||||
const formattedDate = yyymmdd.replace(/\D/g, '')
|
||||
@@ -49,12 +49,6 @@ export const createMigration: CreateMigration = async function createMigration(
|
||||
|
||||
let drizzleJsonBefore = defaultDrizzleSnapshot
|
||||
|
||||
if (this.schemaName) {
|
||||
drizzleJsonBefore.schemas = {
|
||||
[this.schemaName]: this.schemaName,
|
||||
}
|
||||
}
|
||||
|
||||
if (!upSQL) {
|
||||
// Get latest migration snapshot
|
||||
const latestSnapshot = fs
|
||||
@@ -71,7 +65,7 @@ export const createMigration: CreateMigration = async function createMigration(
|
||||
|
||||
const sqlStatementsUp = await generateMigration(drizzleJsonBefore, drizzleJsonAfter)
|
||||
const sqlStatementsDown = await generateMigration(drizzleJsonAfter, drizzleJsonBefore)
|
||||
const sqlExecute = 'await payload.db.drizzle.execute(sql`'
|
||||
const sqlExecute = 'await db.execute(sql`'
|
||||
|
||||
if (sqlStatementsUp?.length) {
|
||||
upSQL = `${sqlExecute}\n ${sqlStatementsUp?.join('\n')}\`)`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DrizzleSnapshotJSON } from 'drizzle-kit/api'
|
||||
import type { DrizzleSnapshotJSON } from 'drizzle-kit/payload'
|
||||
|
||||
export const defaultDrizzleSnapshot: DrizzleSnapshotJSON = {
|
||||
id: '00000000-0000-0000-0000-000000000000',
|
||||
@@ -7,11 +7,10 @@ export const defaultDrizzleSnapshot: DrizzleSnapshotJSON = {
|
||||
schemas: {},
|
||||
tables: {},
|
||||
},
|
||||
dialect: 'postgresql',
|
||||
dialect: 'pg',
|
||||
enums: {},
|
||||
prevId: '00000000-0000-0000-0000-00000000000',
|
||||
schemas: {},
|
||||
sequences: {},
|
||||
tables: {},
|
||||
version: '7',
|
||||
version: '5',
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ export const getMigrationTemplate = ({
|
||||
upSQL,
|
||||
}: MigrationTemplateArgs): string => `import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
|
||||
${imports ? `${imports}\n` : ''}
|
||||
export async function up({ payload, req }: MigrateUpArgs): Promise<void> {
|
||||
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
|
||||
${upSQL}
|
||||
}
|
||||
|
||||
export async function down({ payload, req }: MigrateDownArgs): Promise<void> {
|
||||
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
|
||||
${downSQL}
|
||||
}
|
||||
`
|
||||
|
||||
@@ -32,7 +32,6 @@ import {
|
||||
updateOne,
|
||||
updateVersion,
|
||||
} from '@payloadcms/drizzle'
|
||||
import { type PgSchema, pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'
|
||||
import { createDatabaseAdapter } from 'payload'
|
||||
|
||||
import type { Args, PostgresAdapter } from './types.js'
|
||||
@@ -63,19 +62,12 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter>
|
||||
const migrationDir = findMigrationDir(args.migrationDir)
|
||||
let resolveInitializing
|
||||
let rejectInitializing
|
||||
let adapterSchema: PostgresAdapter['pgSchema']
|
||||
|
||||
const initializing = new Promise<void>((res, rej) => {
|
||||
resolveInitializing = res
|
||||
rejectInitializing = rej
|
||||
})
|
||||
|
||||
if (args.schemaName) {
|
||||
adapterSchema = pgSchema(args.schemaName)
|
||||
} else {
|
||||
adapterSchema = { enum: pgEnum, table: pgTable }
|
||||
}
|
||||
|
||||
return createDatabaseAdapter<PostgresAdapter>({
|
||||
name: 'postgres',
|
||||
defaultDrizzleSnapshot,
|
||||
@@ -91,7 +83,7 @@ export function postgresAdapter(args: Args): DatabaseAdapterObj<PostgresAdapter>
|
||||
localesSuffix: args.localesSuffix || '_locales',
|
||||
logger: args.logger,
|
||||
operators: operatorMap,
|
||||
pgSchema: adapterSchema,
|
||||
pgSchema: undefined,
|
||||
pool: undefined,
|
||||
poolOptions: args.pool,
|
||||
push: args.push,
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
import type { Init, SanitizedCollectionConfig } from 'payload'
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { SanitizedCollectionConfig } from 'payload'
|
||||
import type { Init } from 'payload'
|
||||
|
||||
import { createTableName } from '@payloadcms/drizzle'
|
||||
import { pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'
|
||||
import { buildVersionCollectionFields, buildVersionGlobalFields } from 'payload'
|
||||
import toSnakeCase from 'to-snake-case'
|
||||
|
||||
import type { PostgresAdapter } from './types.js'
|
||||
|
||||
import { createTableName } from '../../drizzle/src/createTableName.js'
|
||||
import { buildTable } from './schema/build.js'
|
||||
|
||||
export const init: Init = function init(this: PostgresAdapter) {
|
||||
if (this.schemaName) {
|
||||
this.pgSchema = pgSchema(this.schemaName)
|
||||
} else {
|
||||
this.pgSchema = { table: pgTable }
|
||||
}
|
||||
if (this.payload.config.localization) {
|
||||
this.enums.enum__locales = this.pgSchema.enum(
|
||||
this.enums.enum__locales = pgEnum(
|
||||
'_locales',
|
||||
this.payload.config.localization.locales.map(({ code }) => code) as [string, ...string[]],
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { TransactionPg } from '@payloadcms/drizzle/types'
|
||||
import type { DrizzleSnapshotJSON } from 'drizzle-kit/api'
|
||||
import type { DrizzleSnapshotJSON } from 'drizzle-kit/payload'
|
||||
import type { Payload, PayloadRequest } from 'payload'
|
||||
|
||||
import { sql } from 'drizzle-orm'
|
||||
@@ -43,7 +43,7 @@ export const migratePostgresV2toV3 = async ({ debug, payload, req }: Args) => {
|
||||
const dir = payload.db.migrationDir
|
||||
|
||||
// get the drizzle migrateUpSQL from drizzle using the last schema
|
||||
const { generateDrizzleJson, generateMigration } = require('drizzle-kit/api')
|
||||
const { generateDrizzleJson, generateMigration } = require('drizzle-kit/payload')
|
||||
const drizzleJsonAfter = generateDrizzleJson(adapter.schema)
|
||||
|
||||
// Get the previous migration snapshot
|
||||
|
||||
@@ -2,4 +2,4 @@ import type { RequireDrizzleKit } from '@payloadcms/drizzle/types'
|
||||
|
||||
import { createRequire } from 'module'
|
||||
const require = createRequire(import.meta.url)
|
||||
export const requireDrizzleKit: RequireDrizzleKit = () => require('drizzle-kit/api')
|
||||
export const requireDrizzleKit: RequireDrizzleKit = () => require('drizzle-kit/payload')
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
import type {
|
||||
ForeignKeyBuilder,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { index, uniqueIndex } from 'drizzle-orm/pg-core'
|
||||
|
||||
import type { GenericColumn } from '../types.js'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
import type { IndexBuilder, PgColumnBuilder } from 'drizzle-orm/pg-core'
|
||||
import type { Field, TabAsField } from 'payload'
|
||||
@@ -18,6 +19,7 @@ import {
|
||||
integer,
|
||||
jsonb,
|
||||
numeric,
|
||||
pgEnum,
|
||||
text,
|
||||
timestamp,
|
||||
varchar,
|
||||
@@ -33,7 +35,6 @@ import { buildTable } from './build.js'
|
||||
import { createIndex } from './createIndex.js'
|
||||
import { idToUUID } from './idToUUID.js'
|
||||
import { parentIDColumnMap } from './parentIDColumnMap.js'
|
||||
import { withDefault } from './withDefault.js'
|
||||
|
||||
type Args = {
|
||||
adapter: PostgresAdapter
|
||||
@@ -169,14 +170,14 @@ export const traverseFields = ({
|
||||
)
|
||||
}
|
||||
} else {
|
||||
targetTable[fieldName] = withDefault(varchar(columnName), field)
|
||||
targetTable[fieldName] = varchar(columnName)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'email':
|
||||
case 'code':
|
||||
case 'textarea': {
|
||||
targetTable[fieldName] = withDefault(varchar(columnName), field)
|
||||
targetTable[fieldName] = varchar(columnName)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -198,26 +199,23 @@ export const traverseFields = ({
|
||||
)
|
||||
}
|
||||
} else {
|
||||
targetTable[fieldName] = withDefault(numeric(columnName), field)
|
||||
targetTable[fieldName] = numeric(columnName)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'richText':
|
||||
case 'json': {
|
||||
targetTable[fieldName] = withDefault(jsonb(columnName), field)
|
||||
targetTable[fieldName] = jsonb(columnName)
|
||||
break
|
||||
}
|
||||
|
||||
case 'date': {
|
||||
targetTable[fieldName] = withDefault(
|
||||
timestamp(columnName, {
|
||||
mode: 'string',
|
||||
precision: 3,
|
||||
withTimezone: true,
|
||||
}),
|
||||
field,
|
||||
)
|
||||
targetTable[fieldName] = timestamp(columnName, {
|
||||
mode: 'string',
|
||||
precision: 3,
|
||||
withTimezone: true,
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
@@ -236,7 +234,7 @@ export const traverseFields = ({
|
||||
throwValidationError,
|
||||
})
|
||||
|
||||
adapter.enums[enumName] = adapter.pgSchema.enum(
|
||||
adapter.enums[enumName] = pgEnum(
|
||||
enumName,
|
||||
field.options.map((option) => {
|
||||
if (optionIsObject(option)) {
|
||||
@@ -313,13 +311,13 @@ export const traverseFields = ({
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
targetTable[fieldName] = withDefault(adapter.enums[enumName](fieldName), field)
|
||||
targetTable[fieldName] = adapter.enums[enumName](fieldName)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'checkbox': {
|
||||
targetTable[fieldName] = withDefault(boolean(columnName), field)
|
||||
targetTable[fieldName] = boolean(columnName)
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import type { PgColumnBuilder } from 'drizzle-orm/pg-core'
|
||||
import type { FieldAffectingData } from 'payload'
|
||||
|
||||
export const withDefault = (
|
||||
column: PgColumnBuilder,
|
||||
field: FieldAffectingData,
|
||||
): PgColumnBuilder => {
|
||||
if (typeof field.defaultValue === 'undefined' || typeof field.defaultValue === 'function')
|
||||
return column
|
||||
|
||||
if (typeof field.defaultValue === 'string' && field.defaultValue.includes("'")) {
|
||||
const escapedString = field.defaultValue.replaceAll("'", "''")
|
||||
return column.default(escapedString)
|
||||
}
|
||||
|
||||
return column.default(field.defaultValue)
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import type {
|
||||
DrizzleAdapter,
|
||||
TransactionPg,
|
||||
} from '@payloadcms/drizzle/types'
|
||||
import type { DrizzleSnapshotJSON } from 'drizzle-kit/api'
|
||||
import type { DrizzleSnapshotJSON } from 'drizzle-kit/payload'
|
||||
import type {
|
||||
ColumnBaseConfig,
|
||||
ColumnDataType,
|
||||
@@ -21,7 +21,6 @@ import type {
|
||||
PgSchema,
|
||||
PgTableWithColumns,
|
||||
PgTransactionConfig,
|
||||
pgEnum,
|
||||
} from 'drizzle-orm/pg-core'
|
||||
import type { PgTableFn } from 'drizzle-orm/pg-core/table'
|
||||
import type { Payload, PayloadRequest } from 'payload'
|
||||
@@ -107,13 +106,6 @@ type PostgresDrizzleAdapter = Omit<
|
||||
| 'relations'
|
||||
>
|
||||
|
||||
type Schema =
|
||||
| {
|
||||
enum: typeof pgEnum
|
||||
table: PgTableFn
|
||||
}
|
||||
| PgSchema
|
||||
|
||||
export type PostgresAdapter = {
|
||||
countDistinct: CountDistinct
|
||||
defaultDrizzleSnapshot: DrizzleSnapshotJSON
|
||||
@@ -133,7 +125,7 @@ export type PostgresAdapter = {
|
||||
localesSuffix?: string
|
||||
logger: DrizzleConfig['logger']
|
||||
operators: Operators
|
||||
pgSchema?: Schema
|
||||
pgSchema?: { table: PgTableFn } | PgSchema
|
||||
pool: Pool
|
||||
poolOptions: Args['pool']
|
||||
push: boolean
|
||||
@@ -141,6 +133,7 @@ export type PostgresAdapter = {
|
||||
relations: Record<string, GenericRelation>
|
||||
relationshipsSuffix?: string
|
||||
resolveInitializing: () => void
|
||||
schema: Record<string, GenericEnum | GenericRelation | GenericTable>
|
||||
schemaName?: Args['schemaName']
|
||||
sessions: {
|
||||
[id: string]: {
|
||||
@@ -163,8 +156,6 @@ declare module 'payload' {
|
||||
export interface DatabaseAdapter
|
||||
extends Omit<Args, 'idType' | 'logger' | 'migrationDir' | 'pool'>,
|
||||
DrizzleAdapter {
|
||||
beginTransaction: (options?: PgTransactionConfig) => Promise<null | number | string>
|
||||
drizzle: PostgresDB
|
||||
enums: Record<string, GenericEnum>
|
||||
/**
|
||||
* An object keyed on each table, with a key value pair where the constraint name is the key, followed by the dot-notation field name
|
||||
@@ -182,7 +173,7 @@ declare module 'payload' {
|
||||
rejectInitializing: () => void
|
||||
relationshipsSuffix?: string
|
||||
resolveInitializing: () => void
|
||||
schema: Record<string, unknown>
|
||||
schema: Record<string, GenericEnum | GenericRelation | GenericTable>
|
||||
schemaName?: Args['schemaName']
|
||||
tableNameMap: Map<string, string>
|
||||
versionsSuffix?: string
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-sqlite",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.36",
|
||||
"description": "The officially supported SQLite database adapter for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
@@ -46,8 +46,8 @@
|
||||
"@libsql/client": "^0.6.2",
|
||||
"@payloadcms/drizzle": "workspace:*",
|
||||
"console-table-printer": "2.11.2",
|
||||
"drizzle-kit": "0.23.2",
|
||||
"drizzle-orm": "0.32.1",
|
||||
"drizzle-kit": "0.20.14-1f2c838",
|
||||
"drizzle-orm": "0.29.4",
|
||||
"prompts": "2.4.2",
|
||||
"to-snake-case": "1.0.0",
|
||||
"uuid": "9.0.0"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DrizzleSnapshotJSON } from 'drizzle-kit/api'
|
||||
import type { DrizzleSnapshotJSON } from 'drizzle-kit/payload'
|
||||
import type { CreateMigration } from 'payload'
|
||||
|
||||
import fs from 'fs'
|
||||
@@ -25,7 +25,7 @@ export const createMigration: CreateMigration = async function createMigration(
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir)
|
||||
}
|
||||
const { generateSQLiteDrizzleJson, generateSQLiteMigration } = require('drizzle-kit/api')
|
||||
const { generateSQLiteDrizzleJson, generateSQLiteMigration } = require('drizzle-kit/payload')
|
||||
const drizzleJsonAfter = await generateSQLiteDrizzleJson(this.schema)
|
||||
const [yyymmdd, hhmmss] = new Date().toISOString().split('T')
|
||||
const formattedDate = yyymmdd.replace(/\D/g, '')
|
||||
@@ -66,7 +66,7 @@ export const createMigration: CreateMigration = async function createMigration(
|
||||
const sqlStatementsUp = await generateSQLiteMigration(drizzleJsonBefore, drizzleJsonAfter)
|
||||
const sqlStatementsDown = await generateSQLiteMigration(drizzleJsonAfter, drizzleJsonBefore)
|
||||
// need to create tables as separate statements
|
||||
const sqlExecute = 'await payload.db.drizzle.run(sql`'
|
||||
const sqlExecute = 'await db.run(sql`'
|
||||
|
||||
if (sqlStatementsUp?.length) {
|
||||
upSQL = sqlStatementsUp
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DrizzleSQLiteSnapshotJSON } from 'drizzle-kit/api'
|
||||
import type { DrizzleSQLiteSnapshotJSON } from 'drizzle-kit/payload'
|
||||
|
||||
export const defaultDrizzleSnapshot: DrizzleSQLiteSnapshotJSON = {
|
||||
id: '00000000-0000-0000-0000-000000000000',
|
||||
@@ -10,5 +10,5 @@ export const defaultDrizzleSnapshot: DrizzleSQLiteSnapshotJSON = {
|
||||
enums: {},
|
||||
prevId: '00000000-0000-0000-0000-00000000000',
|
||||
tables: {},
|
||||
version: '6',
|
||||
version: '3',
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ export const getMigrationTemplate = ({
|
||||
upSQL,
|
||||
}: MigrationTemplateArgs): string => `import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-sqlite'
|
||||
${imports ? `${imports}\n` : ''}
|
||||
export async function up({ payload, req }: MigrateUpArgs): Promise<void> {
|
||||
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
|
||||
${upSQL}
|
||||
}
|
||||
|
||||
export async function down({ payload, req }: MigrateDownArgs): Promise<void> {
|
||||
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
|
||||
${downSQL}
|
||||
}
|
||||
`
|
||||
|
||||
@@ -105,7 +105,7 @@ export function sqliteAdapter(args: Args): DatabaseAdapterObj<SQLiteAdapter> {
|
||||
versionsSuffix: args.versionsSuffix || '_v',
|
||||
|
||||
// DatabaseAdapter
|
||||
beginTransaction: args.transactionOptions ? beginTransaction : undefined,
|
||||
beginTransaction: args.transactionOptions === false ? undefined : beginTransaction,
|
||||
commitTransaction,
|
||||
connect,
|
||||
convertPathToJSONTraversal,
|
||||
|
||||
@@ -10,6 +10,6 @@ export const requireDrizzleKit: RequireDrizzleKit = () => {
|
||||
const {
|
||||
generateSQLiteDrizzleJson: generateDrizzleJson,
|
||||
pushSQLiteSchema: pushSchema,
|
||||
} = require('drizzle-kit/api')
|
||||
} = require('drizzle-kit/payload')
|
||||
return { generateDrizzleJson, pushSchema }
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { ColumnDataType, Relation } from 'drizzle-orm'
|
||||
import type {
|
||||
AnySQLiteColumn,
|
||||
ForeignKeyBuilder,
|
||||
IndexBuilder,
|
||||
SQLiteColumn,
|
||||
SQLiteColumnBuilder,
|
||||
SQLiteTableWithColumns,
|
||||
UniqueConstraintBuilder,
|
||||
@@ -31,7 +32,18 @@ import { traverseFields } from './traverseFields.js'
|
||||
export type BaseExtraConfig = Record<
|
||||
string,
|
||||
(cols: {
|
||||
[x: string]: AnySQLiteColumn
|
||||
[x: string]: SQLiteColumn<{
|
||||
baseColumn: never
|
||||
columnType: string
|
||||
data: unknown
|
||||
dataType: ColumnDataType
|
||||
driverParam: unknown
|
||||
enumValues: string[]
|
||||
hasDefault: false
|
||||
name: string
|
||||
notNull: false
|
||||
tableName: string
|
||||
}>
|
||||
}) => ForeignKeyBuilder | IndexBuilder | UniqueConstraintBuilder
|
||||
>
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { AnySQLiteColumn} from 'drizzle-orm/sqlite-core';
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { index, uniqueIndex } from 'drizzle-orm/sqlite-core'
|
||||
|
||||
import type { GenericColumn } from '../types.js'
|
||||
|
||||
type CreateIndexArgs = {
|
||||
columnName: string
|
||||
name: string | string[]
|
||||
@@ -10,7 +11,7 @@ type CreateIndexArgs = {
|
||||
}
|
||||
|
||||
export const createIndex = ({ name, columnName, tableName, unique }: CreateIndexArgs) => {
|
||||
return (table: { [x: string]: AnySQLiteColumn }) => {
|
||||
return (table: { [x: string]: GenericColumn }) => {
|
||||
let columns
|
||||
if (Array.isArray(name)) {
|
||||
columns = name
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
import type { IndexBuilder, SQLiteColumnBuilder } from 'drizzle-orm/sqlite-core'
|
||||
import type { Field, TabAsField } from 'payload'
|
||||
@@ -29,7 +30,6 @@ import { buildTable } from './build.js'
|
||||
import { createIndex } from './createIndex.js'
|
||||
import { getIDColumn } from './getIDColumn.js'
|
||||
import { idToUUID } from './idToUUID.js'
|
||||
import { withDefault } from './withDefault.js'
|
||||
|
||||
type Args = {
|
||||
adapter: SQLiteAdapter
|
||||
@@ -166,14 +166,14 @@ export const traverseFields = ({
|
||||
)
|
||||
}
|
||||
} else {
|
||||
targetTable[fieldName] = withDefault(text(columnName), field)
|
||||
targetTable[fieldName] = text(columnName)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'email':
|
||||
case 'code':
|
||||
case 'textarea': {
|
||||
targetTable[fieldName] = withDefault(text(columnName), field)
|
||||
targetTable[fieldName] = text(columnName)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -195,19 +195,19 @@ export const traverseFields = ({
|
||||
)
|
||||
}
|
||||
} else {
|
||||
targetTable[fieldName] = withDefault(numeric(columnName), field)
|
||||
targetTable[fieldName] = numeric(columnName)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'richText':
|
||||
case 'json': {
|
||||
targetTable[fieldName] = withDefault(text(columnName, { mode: 'json' }), field)
|
||||
targetTable[fieldName] = text(columnName, { mode: 'json' })
|
||||
break
|
||||
}
|
||||
|
||||
case 'date': {
|
||||
targetTable[fieldName] = withDefault(text(columnName), field)
|
||||
targetTable[fieldName] = text(columnName)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -295,13 +295,13 @@ export const traverseFields = ({
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
targetTable[fieldName] = withDefault(text(fieldName, { enum: options }), field)
|
||||
targetTable[fieldName] = text(fieldName, { enum: options })
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'checkbox': {
|
||||
targetTable[fieldName] = withDefault(integer(columnName, { mode: 'boolean' }), field)
|
||||
targetTable[fieldName] = integer(columnName, { mode: 'boolean' })
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import type { SQLiteColumnBuilder } from 'drizzle-orm/sqlite-core'
|
||||
import type { FieldAffectingData } from 'payload'
|
||||
|
||||
export const withDefault = (
|
||||
column: SQLiteColumnBuilder,
|
||||
field: FieldAffectingData,
|
||||
): SQLiteColumnBuilder => {
|
||||
if (typeof field.defaultValue === 'undefined' || typeof field.defaultValue === 'function')
|
||||
return column
|
||||
|
||||
if (typeof field.defaultValue === 'string' && field.defaultValue.includes("'")) {
|
||||
const escapedString = field.defaultValue.replaceAll("'", "''")
|
||||
return column.default(escapedString)
|
||||
}
|
||||
|
||||
return column.default(field.defaultValue)
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { Client, Config, ResultSet } from '@libsql/client'
|
||||
import type { Operators } from '@payloadcms/drizzle'
|
||||
import type { BuildQueryJoinAliases, DrizzleAdapter } from '@payloadcms/drizzle/types'
|
||||
import type { DrizzleConfig, Relation, Relations, SQL } from 'drizzle-orm'
|
||||
import type { ColumnDataType, DrizzleConfig, Relation, Relations, SQL } from 'drizzle-orm'
|
||||
import type { LibSQLDatabase } from 'drizzle-orm/libsql'
|
||||
import type {
|
||||
AnySQLiteColumn,
|
||||
SQLiteColumn,
|
||||
SQLiteInsertOnConflictDoUpdateConfig,
|
||||
SQLiteTableWithColumns,
|
||||
SQLiteTransactionConfig,
|
||||
@@ -25,8 +25,24 @@ export type Args = {
|
||||
versionsSuffix?: string
|
||||
}
|
||||
|
||||
export type GenericColumn = SQLiteColumn<
|
||||
{
|
||||
baseColumn: never
|
||||
columnType: string
|
||||
data: unknown
|
||||
dataType: ColumnDataType
|
||||
driverParam: unknown
|
||||
enumValues: string[]
|
||||
hasDefault: false
|
||||
name: string
|
||||
notNull: false
|
||||
tableName: string
|
||||
},
|
||||
object
|
||||
>
|
||||
|
||||
export type GenericColumns = {
|
||||
[x: string]: AnySQLiteColumn
|
||||
[x: string]: GenericColumn
|
||||
}
|
||||
|
||||
export type GenericTable = SQLiteTableWithColumns<{
|
||||
@@ -116,10 +132,12 @@ export type SQLiteAdapter = {
|
||||
export type IDType = 'integer' | 'numeric' | 'text'
|
||||
|
||||
export type MigrateUpArgs = {
|
||||
db: LibSQLDatabase
|
||||
payload: Payload
|
||||
req?: Partial<PayloadRequest>
|
||||
}
|
||||
export type MigrateDownArgs = {
|
||||
db: LibSQLDatabase
|
||||
payload: Payload
|
||||
req?: Partial<PayloadRequest>
|
||||
}
|
||||
@@ -128,8 +146,6 @@ declare module 'payload' {
|
||||
export interface DatabaseAdapter
|
||||
extends Omit<Args, 'idType' | 'logger' | 'migrationDir' | 'pool'>,
|
||||
DrizzleAdapter {
|
||||
beginTransaction: (options?: SQLiteTransactionConfig) => Promise<null | number | string>
|
||||
drizzle: LibSQLDatabase
|
||||
/**
|
||||
* An object keyed on each table, with a key value pair where the constraint name is the key, followed by the dot-notation field name
|
||||
* Used for returning properly formed errors from unique fields
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/drizzle",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.36",
|
||||
"description": "A library of shared functions used by different payload database adapters",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
@@ -39,7 +39,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"console-table-printer": "2.11.2",
|
||||
"drizzle-orm": "0.32.1",
|
||||
"drizzle-orm": "0.29.4",
|
||||
"prompts": "2.4.2",
|
||||
"to-snake-case": "1.0.0",
|
||||
"uuid": "9.0.0"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Count , SanitizedCollectionConfig } from 'payload'
|
||||
import type { Count } from 'payload'
|
||||
import type { SanitizedCollectionConfig } from 'payload'
|
||||
|
||||
import toSnakeCase from 'to-snake-case'
|
||||
|
||||
@@ -14,7 +15,7 @@ export const count: Count = async function count(
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(collectionConfig.slug))
|
||||
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
|
||||
const { joins, where } = await buildQuery({
|
||||
adapter: this,
|
||||
|
||||
@@ -10,7 +10,7 @@ export const create: Create = async function create(
|
||||
this: DrizzleAdapter,
|
||||
{ collection: collectionSlug, data, req },
|
||||
) {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const collection = this.payload.collections[collectionSlug].config
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(collection.slug))
|
||||
|
||||
@@ -10,7 +10,7 @@ export async function createGlobal<T extends Record<string, unknown>>(
|
||||
this: DrizzleAdapter,
|
||||
{ slug, data, req = {} as PayloadRequest }: CreateGlobalArgs,
|
||||
): Promise<T> {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const globalConfig = this.payload.globals.config.find((config) => config.slug === slug)
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(globalConfig.slug))
|
||||
|
||||
@@ -12,7 +12,7 @@ export async function createGlobalVersion<T extends TypeWithID>(
|
||||
this: DrizzleAdapter,
|
||||
{ autosave, globalSlug, req = {} as PayloadRequest, versionData }: CreateGlobalVersionArgs,
|
||||
) {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const global = this.payload.globals.config.find(({ slug }) => slug === globalSlug)
|
||||
|
||||
const tableName = this.tableNameMap.get(`_${toSnakeCase(global.slug)}${this.versionsSuffix}`)
|
||||
|
||||
@@ -18,7 +18,7 @@ export async function createVersion<T extends TypeWithID>(
|
||||
versionData,
|
||||
}: CreateVersionArgs<T>,
|
||||
) {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const collection = this.payload.collections[collectionSlug].config
|
||||
const defaultTableName = toSnakeCase(collection.slug)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export const deleteMany: DeleteMany = async function deleteMany(
|
||||
this: DrizzleAdapter,
|
||||
{ collection, req = {} as PayloadRequest, where },
|
||||
) {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const collectionConfig = this.payload.collections[collection].config
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(collectionConfig.slug))
|
||||
|
||||
@@ -14,7 +14,7 @@ export const deleteOne: DeleteOne = async function deleteOne(
|
||||
this: DrizzleAdapter,
|
||||
{ collection: collectionSlug, req = {} as PayloadRequest, where: whereArg },
|
||||
) {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const collection = this.payload.collections[collectionSlug].config
|
||||
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(collection.slug))
|
||||
|
||||
@@ -12,7 +12,7 @@ export const deleteVersions: DeleteVersions = async function deleteVersion(
|
||||
this: DrizzleAdapter,
|
||||
{ collection, locale, req = {} as PayloadRequest, where: where },
|
||||
) {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config
|
||||
|
||||
const tableName = this.tableNameMap.get(
|
||||
|
||||
@@ -6,7 +6,6 @@ import type { DrizzleAdapter, DrizzleTransaction } from '../types.js'
|
||||
|
||||
export const beginTransaction: BeginTransaction = async function beginTransaction(
|
||||
this: DrizzleAdapter,
|
||||
options: DrizzleAdapter['transactionOptions'],
|
||||
) {
|
||||
let id
|
||||
try {
|
||||
@@ -42,7 +41,7 @@ export const beginTransaction: BeginTransaction = async function beginTransactio
|
||||
}
|
||||
transactionReady()
|
||||
})
|
||||
}, options || this.transactionOptions)
|
||||
}, this.transactionOptions)
|
||||
.catch(() => {
|
||||
// swallow
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Field, SanitizedConfig, TabAsField } from 'payload'
|
||||
|
||||
import type { Field, SanitizedConfig , TabAsField } from 'payload'
|
||||
|
||||
import { fieldAffectsData } from 'payload/shared'
|
||||
|
||||
|
||||
@@ -120,7 +120,6 @@ export type RequireDrizzleKit = () => {
|
||||
pushSchema: (
|
||||
schema: Record<string, unknown>,
|
||||
drizzle: DrizzleAdapter['drizzle'],
|
||||
filterSchema?: string[],
|
||||
) => Promise<{ apply; hasDataLoss; warnings }>
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ export const updateOne: UpdateOne = async function updateOne(
|
||||
this: DrizzleAdapter,
|
||||
{ id, collection: collectionSlug, data, draft, locale, req, where: whereArg },
|
||||
) {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const collection = this.payload.collections[collectionSlug].config
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(collection.slug))
|
||||
const whereToUse = whereArg || { id: { equals: id } }
|
||||
|
||||
@@ -10,7 +10,7 @@ export async function updateGlobal<T extends Record<string, unknown>>(
|
||||
this: DrizzleAdapter,
|
||||
{ slug, data, req = {} as PayloadRequest }: UpdateGlobalArgs,
|
||||
): Promise<T> {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const globalConfig = this.payload.globals.config.find((config) => config.slug === slug)
|
||||
const tableName = this.tableNameMap.get(toSnakeCase(globalConfig.slug))
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export async function updateGlobalVersion<T extends TypeWithID>(
|
||||
where: whereArg,
|
||||
}: UpdateGlobalVersionArgs<T>,
|
||||
) {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const globalConfig: SanitizedGlobalConfig = this.payload.globals.config.find(
|
||||
({ slug }) => slug === global,
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ export async function updateVersion<T extends TypeWithID>(
|
||||
where: whereArg,
|
||||
}: UpdateVersionArgs<T>,
|
||||
) {
|
||||
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
|
||||
const db = this.sessions[await req.transactionID]?.db || this.drizzle
|
||||
const collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config
|
||||
const whereToUse = whereArg || { id: { equals: id } }
|
||||
const tableName = this.tableNameMap.get(
|
||||
|
||||
@@ -4,10 +4,8 @@ import { fieldAffectsData, fieldHasSubFields } from 'payload/shared'
|
||||
|
||||
export const hasLocalesTable = (fields: Field[]): boolean => {
|
||||
return fields.some((field) => {
|
||||
// arrays always get a separate table
|
||||
if (field.type === 'array') return false
|
||||
if (fieldAffectsData(field) && field.localized) return true
|
||||
if (fieldHasSubFields(field)) return hasLocalesTable(field.fields)
|
||||
if (fieldHasSubFields(field) && field.type !== 'array') return hasLocalesTable(field.fields)
|
||||
if (field.type === 'tabs') return field.tabs.some((tab) => hasLocalesTable(tab.fields))
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ export const migrationTableExists = async (adapter: DrizzleAdapter): Promise<boo
|
||||
|
||||
if (adapter.name === 'postgres') {
|
||||
const prependSchema = adapter.schemaName ? `"${adapter.schemaName}".` : ''
|
||||
statement = `SELECT to_regclass('${prependSchema}"payload_migrations"') AS exists;`
|
||||
statement = `SELECT to_regclass('${prependSchema}"payload_migrations"') exists;`
|
||||
}
|
||||
|
||||
if (adapter.name === 'sqlite') {
|
||||
|
||||
@@ -12,11 +12,7 @@ export const pushDevSchema = async (adapter: DrizzleAdapter) => {
|
||||
const { pushSchema } = adapter.requireDrizzleKit()
|
||||
|
||||
// This will prompt if clarifications are needed for Drizzle to push new schema
|
||||
const { apply, hasDataLoss, warnings } = await pushSchema(
|
||||
adapter.schema,
|
||||
adapter.drizzle,
|
||||
adapter.schemaName ? [adapter.schemaName] : undefined,
|
||||
)
|
||||
const { apply, hasDataLoss, warnings } = await pushSchema(adapter.schema, adapter.drizzle)
|
||||
|
||||
if (warnings.length) {
|
||||
let message = `Warnings detected during schema push: \n\n${warnings.join('\n')}\n\n`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-nodemailer",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"description": "Payload Nodemailer Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/email-resend",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"description": "Payload Resend Email Adapter",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -39,7 +39,7 @@ export const index = deepMerge(
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'react-hooks/rules-of-hooks': 'error',
|
||||
'react-hooks/rules-of-hooks': 'warn',
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"eslint-plugin-react-hooks": "5.1.0-rc-85acf2d195-20240711",
|
||||
"eslint-plugin-regexp": "2.6.0",
|
||||
"globals": "15.8.0",
|
||||
"typescript": "5.5.4",
|
||||
"typescript": "5.5.3",
|
||||
"typescript-eslint": "7.16.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"eslint-plugin-react-hooks": "5.1.0-rc-85acf2d195-20240711",
|
||||
"eslint-plugin-regexp": "2.6.0",
|
||||
"globals": "15.8.0",
|
||||
"typescript": "5.5.4",
|
||||
"typescript": "5.5.3",
|
||||
"typescript-eslint": "7.16.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/graphql",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export { GraphQLJSON, GraphQLJSONObject } from '../packages/graphql-type-json/index.js'
|
||||
export { buildPaginatedListType } from '../schema/buildPaginatedListType.js'
|
||||
export * as GraphQL from 'graphql'
|
||||
export { default as GraphQL } from 'graphql'
|
||||
|
||||
@@ -7,7 +7,6 @@ import type { Context } from '../types.js'
|
||||
export type Resolver = (
|
||||
_: unknown,
|
||||
args: {
|
||||
draft?: boolean
|
||||
id: number | string
|
||||
},
|
||||
context: {
|
||||
@@ -21,7 +20,6 @@ export default function restoreVersionResolver(collection: Collection): Resolver
|
||||
id: args.id,
|
||||
collection,
|
||||
depth: 0,
|
||||
draft: args.draft,
|
||||
req: isolateObjectProperty(context.req, 'transactionID'),
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import type { Context } from '../types.js'
|
||||
type Resolver = (
|
||||
_: unknown,
|
||||
args: {
|
||||
draft?: boolean
|
||||
id: number | string
|
||||
},
|
||||
context: {
|
||||
@@ -19,7 +18,6 @@ export default function restoreVersionResolver(globalConfig: SanitizedGlobalConf
|
||||
const options = {
|
||||
id: args.id,
|
||||
depth: 0,
|
||||
draft: args.draft,
|
||||
globalConfig,
|
||||
req: isolateObjectProperty(context.req, 'transactionID'),
|
||||
}
|
||||
|
||||
@@ -342,7 +342,6 @@ function initCollectionsGraphQL({ config, graphqlResult }: InitCollectionsGraphQ
|
||||
type: collection.graphQL.type,
|
||||
args: {
|
||||
id: { type: versionIDType },
|
||||
draft: { type: GraphQLBoolean },
|
||||
},
|
||||
resolve: restoreVersionResolver(collection),
|
||||
}
|
||||
|
||||
@@ -133,7 +133,6 @@ function initGlobalsGraphQL({ config, graphqlResult }: InitGlobalsGraphQLArgs):
|
||||
type: graphqlResult.globals.graphQL[slug].versionType,
|
||||
args: {
|
||||
id: { type: idType },
|
||||
draft: { type: GraphQLBoolean },
|
||||
...(config.localization
|
||||
? {
|
||||
fallbackLocale: { type: graphqlResult.types.fallbackLocaleInputType },
|
||||
@@ -172,7 +171,6 @@ function initGlobalsGraphQL({ config, graphqlResult }: InitGlobalsGraphQLArgs):
|
||||
type: graphqlResult.globals.graphQL[slug].type,
|
||||
args: {
|
||||
id: { type: idType },
|
||||
draft: { type: GraphQLBoolean },
|
||||
},
|
||||
resolve: restoreVersionResolver(global),
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-react",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"description": "The official React SDK for Payload Live Preview",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview-vue",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"description": "The official Vue SDK for Payload Live Preview",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/live-preview",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"description": "The official live preview JavaScript SDK for Payload",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/next",
|
||||
"version": "3.0.0-beta.73",
|
||||
"version": "3.0.0-beta.68",
|
||||
"homepage": "https://payloadcms.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: var(--style-radius-s);
|
||||
border-radius: 2px;
|
||||
background-color: var(--theme-elevation-50);
|
||||
opacity: 0;
|
||||
}
|
||||
@@ -51,7 +51,6 @@
|
||||
}
|
||||
|
||||
&--active {
|
||||
font-weight: 600;
|
||||
&::before {
|
||||
opacity: 1;
|
||||
background-color: var(--theme-elevation-100);
|
||||
@@ -79,15 +78,14 @@
|
||||
gap: 4px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height: base(1.2);
|
||||
padding: base(0.2) base(0.6);
|
||||
padding: calc(var(--base) / 2) calc(var(--base));
|
||||
}
|
||||
|
||||
&__count {
|
||||
line-height: base(0.8);
|
||||
min-width: base(0.8);
|
||||
min-width: 22px;
|
||||
text-align: center;
|
||||
padding: 2px 7px;
|
||||
background-color: var(--theme-elevation-100);
|
||||
border-radius: var(--style-radius-s);
|
||||
border-radius: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
import { useDocumentInfo } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import { baseClass } from '../../Tab/index.js'
|
||||
|
||||
@@ -12,14 +12,13 @@ export const VersionsPill: React.FC = () => {
|
||||
// documents that are version enabled _always_ have at least one version
|
||||
const hasVersions = versions?.totalDocs > 0
|
||||
|
||||
if (hasVersions)
|
||||
return (
|
||||
<span
|
||||
className={[`${baseClass}__count`, hasVersions ? `${baseClass}__count--has-count` : '']
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
>
|
||||
{versions.totalDocs.toString()}
|
||||
</span>
|
||||
)
|
||||
return (
|
||||
<span
|
||||
className={[`${baseClass}__count`, hasVersions ? `${baseClass}__count--has-count` : '']
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
>
|
||||
{hasVersions ? versions.totalDocs.toString() : <Fragment> </Fragment>}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import type { LoginWithUsernameOptions } from 'payload'
|
||||
|
||||
import { EmailField, TextField, useTranslation } from '@payloadcms/ui'
|
||||
import { email, username } from 'payload/shared'
|
||||
import React from 'react'
|
||||
|
||||
type Props = {
|
||||
loginWithUsername?: LoginWithUsernameOptions | false
|
||||
}
|
||||
export const EmailAndUsernameFields: React.FC<Props> = ({ loginWithUsername }) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const requireEmail = !loginWithUsername || (loginWithUsername && loginWithUsername.requireEmail)
|
||||
const requireUsername = loginWithUsername && loginWithUsername.requireUsername
|
||||
const showEmailField =
|
||||
!loginWithUsername || loginWithUsername?.requireEmail || loginWithUsername?.allowEmailLogin
|
||||
const showUsernameField = Boolean(loginWithUsername)
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{showEmailField && (
|
||||
<EmailField
|
||||
autoComplete="email"
|
||||
label={t('general:email')}
|
||||
name="email"
|
||||
path="email"
|
||||
required={requireEmail}
|
||||
validate={email}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showUsernameField && (
|
||||
<TextField
|
||||
label={t('authentication:username')}
|
||||
name="username"
|
||||
path="username"
|
||||
required={requireUsername}
|
||||
validate={username}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
@@ -37,12 +37,10 @@ const Component: React.FC<{
|
||||
<p>{t('general:changesNotSaved')}</p>
|
||||
</div>
|
||||
<div className={`${baseClass}__controls`}>
|
||||
<Button buttonStyle="secondary" onClick={onCancel} size="large">
|
||||
<Button buttonStyle="secondary" onClick={onCancel}>
|
||||
{t('general:stayOnThisPage')}
|
||||
</Button>
|
||||
<Button onClick={onConfirm} size="large">
|
||||
{t('general:leaveAnyway')}
|
||||
</Button>
|
||||
<Button onClick={onConfirm}>{t('general:leaveAnyway')}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@@ -85,18 +85,9 @@ export const DefaultNavClient: React.FC = () => {
|
||||
|
||||
const LinkElement = Link || 'a'
|
||||
|
||||
const activeCollection = window?.location?.pathname
|
||||
?.split('/')
|
||||
.find(
|
||||
(_, index, arr) =>
|
||||
arr[index - 1] === 'collections' || arr[index - 1] === 'globals',
|
||||
)
|
||||
|
||||
return (
|
||||
<LinkElement
|
||||
className={[`${baseClass}__link`, activeCollection === entity?.slug && `active`]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
className={`${baseClass}__link`}
|
||||
href={href}
|
||||
id={id}
|
||||
key={i}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { initI18n, rtlLanguages } from '@payloadcms/translations'
|
||||
import { RootProvider } from '@payloadcms/ui'
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
import { buildComponentMap } from '@payloadcms/ui/utilities/buildComponentMap'
|
||||
import { Merriweather } from 'next/font/google'
|
||||
import { headers as getHeaders, cookies as nextCookies } from 'next/headers.js'
|
||||
import { createClientConfig, parseCookies } from 'payload'
|
||||
import React from 'react'
|
||||
@@ -15,6 +16,14 @@ import { getRequestTheme } from '../../utilities/getRequestTheme.js'
|
||||
import { DefaultEditView } from '../../views/Edit/Default/index.js'
|
||||
import { DefaultListView } from '../../views/List/Default/index.js'
|
||||
|
||||
const merriweather = Merriweather({
|
||||
display: 'swap',
|
||||
style: ['normal', 'italic'],
|
||||
subsets: ['latin'],
|
||||
variable: '--font-serif',
|
||||
weight: ['400', '900'],
|
||||
})
|
||||
|
||||
export const metadata = {
|
||||
description: 'Generated by Next.js',
|
||||
title: 'Next.js',
|
||||
@@ -91,7 +100,7 @@ export const RootLayout = async ({
|
||||
})
|
||||
|
||||
return (
|
||||
<html data-theme={theme} dir={dir} lang={languageCode}>
|
||||
<html className={merriweather.variable} data-theme={theme} dir={dir} lang={languageCode}>
|
||||
<body>
|
||||
<RootProvider
|
||||
componentMap={componentMap}
|
||||
|
||||
@@ -134,8 +134,12 @@ export const POST =
|
||||
resHeaders.append(key, headers[key])
|
||||
}
|
||||
|
||||
if (req.responseHeaders) {
|
||||
mergeHeaders(req.responseHeaders, resHeaders)
|
||||
}
|
||||
|
||||
return new Response(apiResponse.body, {
|
||||
headers: req.responseHeaders ? mergeHeaders(req.responseHeaders, resHeaders) : resHeaders,
|
||||
headers: resHeaders,
|
||||
status: apiResponse.status,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ export const restoreVersion: CollectionRouteHandlerWithID = async ({
|
||||
}) => {
|
||||
const { searchParams } = req
|
||||
const depth = searchParams.get('depth')
|
||||
const draft = searchParams.get('draft')
|
||||
|
||||
const id = sanitizeCollectionID({
|
||||
id: incomingID,
|
||||
@@ -26,7 +25,6 @@ export const restoreVersion: CollectionRouteHandlerWithID = async ({
|
||||
id,
|
||||
collection,
|
||||
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||
draft: draft === 'true' ? true : undefined,
|
||||
req,
|
||||
})
|
||||
|
||||
|
||||
@@ -9,12 +9,10 @@ import { headersWithCors } from '../../../utilities/headersWithCors.js'
|
||||
export const restoreVersion: GlobalRouteHandlerWithID = async ({ id, globalConfig, req }) => {
|
||||
const { searchParams } = req
|
||||
const depth = searchParams.get('depth')
|
||||
const draft = searchParams.get('draft')
|
||||
|
||||
const doc = await restoreVersionOperationGlobal({
|
||||
id,
|
||||
depth: isNumber(depth) ? Number(depth) : undefined,
|
||||
draft: draft === 'true' ? true : undefined,
|
||||
globalConfig,
|
||||
req,
|
||||
})
|
||||
|
||||
@@ -167,13 +167,7 @@ const handleCustomEndpoints = async ({
|
||||
|
||||
if (res instanceof Response) {
|
||||
if (req.responseHeaders) {
|
||||
const mergedResponse = new Response(res.body, {
|
||||
headers: mergeHeaders(req.responseHeaders, res.headers),
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
})
|
||||
|
||||
return mergedResponse
|
||||
mergeHeaders(req.responseHeaders, res.headers)
|
||||
}
|
||||
|
||||
return res
|
||||
@@ -385,13 +379,7 @@ export const GET =
|
||||
|
||||
if (res instanceof Response) {
|
||||
if (req.responseHeaders) {
|
||||
const mergedResponse = new Response(res.body, {
|
||||
headers: mergeHeaders(req.responseHeaders, res.headers),
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
})
|
||||
|
||||
return mergedResponse
|
||||
mergeHeaders(req.responseHeaders, res.headers)
|
||||
}
|
||||
|
||||
return res
|
||||
@@ -567,13 +555,7 @@ export const POST =
|
||||
|
||||
if (res instanceof Response) {
|
||||
if (req.responseHeaders) {
|
||||
const mergedResponse = new Response(res.body, {
|
||||
headers: mergeHeaders(req.responseHeaders, res.headers),
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
})
|
||||
|
||||
return mergedResponse
|
||||
mergeHeaders(req.responseHeaders, res.headers)
|
||||
}
|
||||
|
||||
return res
|
||||
@@ -661,13 +643,7 @@ export const DELETE =
|
||||
|
||||
if (res instanceof Response) {
|
||||
if (req.responseHeaders) {
|
||||
const mergedResponse = new Response(res.body, {
|
||||
headers: mergeHeaders(req.responseHeaders, res.headers),
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
})
|
||||
|
||||
return mergedResponse
|
||||
mergeHeaders(req.responseHeaders, res.headers)
|
||||
}
|
||||
|
||||
return res
|
||||
@@ -756,13 +732,7 @@ export const PATCH =
|
||||
|
||||
if (res instanceof Response) {
|
||||
if (req.responseHeaders) {
|
||||
const mergedResponse = new Response(res.body, {
|
||||
headers: mergeHeaders(req.responseHeaders, res.headers),
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
})
|
||||
|
||||
return mergedResponse
|
||||
mergeHeaders(req.responseHeaders, res.headers)
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
@import 'styles';
|
||||
@import './styles.scss';
|
||||
@import './toasts.scss';
|
||||
@import './colors.scss';
|
||||
|
||||
:root {
|
||||
--base-px: 20;
|
||||
--base-px: 25;
|
||||
--base-body-size: 13;
|
||||
--base: calc((var(--base-px) / var(--base-body-size)) * 1rem);
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
--theme-baseline-body-size: #{$baseline-body-size};
|
||||
--font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
|
||||
sans-serif;
|
||||
--font-serif: Georgia, 'Bitstream Charter', 'Charis SIL', Utopia, 'URW Bookman L', serif;
|
||||
--font-mono: monospace;
|
||||
|
||||
--style-radius-s: #{$style-radius-s};
|
||||
@@ -68,6 +67,12 @@ html {
|
||||
@extend %body;
|
||||
background: var(--theme-bg);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
opacity: 0;
|
||||
|
||||
&[data-theme='dark'],
|
||||
&[data-theme='light'] {
|
||||
opacity: initial;
|
||||
}
|
||||
|
||||
&[data-theme='dark'] {
|
||||
--theme-bg: var(--theme-elevation-0);
|
||||
@@ -106,12 +111,12 @@ body {
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--color-success-250);
|
||||
background: var(--theme-success-500);
|
||||
color: var(--theme-base-800);
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background: var(--color-success-250);
|
||||
background: var(--theme-success-500);
|
||||
color: var(--theme-base-800);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
@import 'vars';
|
||||
@import 'queries';
|
||||
|
||||
.Toastify {
|
||||
.Toastify__toast-container {
|
||||
left: base(5);
|
||||
transform: none;
|
||||
right: base(5);
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.Toastify__toast {
|
||||
padding: base(0.5);
|
||||
border-radius: $style-radius-m;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.Toastify__close-button {
|
||||
align-self: center;
|
||||
opacity: 0.7;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.Toastify__toast--success {
|
||||
color: var(--color-success-900);
|
||||
background: var(--color-success-500);
|
||||
|
||||
.Toastify__progress-bar {
|
||||
background-color: var(--color-success-900);
|
||||
}
|
||||
}
|
||||
|
||||
.Toastify__close-button--success {
|
||||
color: var(--color-success-900);
|
||||
}
|
||||
|
||||
.Toastify__toast--error {
|
||||
background: var(--theme-error-500);
|
||||
color: #fff;
|
||||
|
||||
.Toastify__progress-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.Toastify__close-button--light {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
@include mid-break {
|
||||
.Toastify__toast-container {
|
||||
left: $baseline;
|
||||
right: $baseline;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user