ci: template errors not being caught due. fix: error due to updated generated-types User type (#12973)

This PR consists of two separate changes. One change cannot pass CI
without the other, so both are included in this single PR.


## CI - ensure types are generated

Our website template is currently failing to build due to a type error.
This error was introduced by a change in our generated types.

Our CI did not catch this issue because it wasn't generating types /
import map before attempting to build the templates. This PR updates the
CI to generate types first.

It also updates some CI step names for improved clarity.

## Fix: type error

![Screenshot 2025-06-29 at 12 53
49@2x](https://github.com/user-attachments/assets/962f1513-bc6c-4e12-9b74-9b891c49900b)


This fixes the type error by ensuring we consistently use the _same_
generated `TypedUser` object within payload, instead of `BaseUser`.
Previously, we sometimes used the generated-types user and sometimes the
base user, which was causing type conflicts depending on what the
generated user type was.

It also deprecates the `User` type (which was essentially just
`BaseUser`), as consumers should use `TypedUser` instead. `TypedUser`
will automatically fall back to `BaseUser` if no generated types exists,
but will accept passing it a generated-types User.

Without this change, additional properties added to the user via
generated-types may cause the user object to not be accepted by
functions that only accept a `User` instead of a `TypedUser`, which is
what failed here.

## Templates: re-generate templates to update generated types

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210668927737258
This commit is contained in:
Alessio Gravili
2025-06-29 14:27:50 -07:00
committed by GitHub
parent cfc7adcbc5
commit 4458f74cef
53 changed files with 710 additions and 146 deletions

View File

@@ -1,4 +1,4 @@
name: build
name: ci
on:
pull_request:
@@ -528,7 +528,9 @@ jobs:
# Build listed templates with packed local packages and then runs their int and e2e tests
build-and-test-templates:
runs-on: ubuntu-24.04
needs: build
needs: [changes, build]
if: ${{ needs.changes.outputs.needs_build == 'true' }}
name: build-template-${{ matrix.template }}-${{ matrix.database }}
strategy:
fail-fast: false
matrix:
@@ -558,8 +560,6 @@ jobs:
# - template: with-vercel-website
# database: postgres
name: ${{ matrix.template }}-${{ matrix.database }}
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres

View File

@@ -1,4 +1,4 @@
import type { User } from 'payload'
import type { TypedUser } from 'payload'
import { formatAdminURL } from 'payload/shared'
import * as qs from 'qs-esm'
@@ -7,7 +7,7 @@ type Args = {
config
route: string
searchParams: { [key: string]: string | string[] }
user?: User
user?: TypedUser
}
export const handleAuthRedirect = ({ config, route, searchParams, user }: Args): string => {

View File

@@ -6,7 +6,7 @@ import type {
PayloadRequest,
SanitizedConfig,
SanitizedPermissions,
User,
TypedUser,
} from 'payload'
import { initI18n } from '@payloadcms/translations'
@@ -37,7 +37,7 @@ type PartialResult = {
languageCode: AcceptedLanguages
payload: Payload
responseHeaders: Headers
user: null | User
user: null | TypedUser
}
// Create cache instances for different parts of our application

View File

@@ -1,5 +1,5 @@
'use client'
import type { User } from 'payload'
import type { TypedUser } from 'payload'
import { Button, ConfirmationModal, toast, useModal, useTranslation } from '@payloadcms/ui'
import * as qs from 'qs-esm'
@@ -9,7 +9,7 @@ const confirmResetModalSlug = 'confirm-reset-modal'
export const ResetPreferences: React.FC<{
readonly apiRoute: string
readonly user?: User
readonly user?: TypedUser
}> = ({ apiRoute, user }) => {
const { openModal } = useModal()
const { t } = useTranslation()

View File

@@ -1,5 +1,5 @@
import type { I18n } from '@payloadcms/translations'
import type { BasePayload, Config, LanguageOptions, User } from 'payload'
import type { BasePayload, Config, LanguageOptions, TypedUser } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
@@ -17,7 +17,7 @@ export const Settings: React.FC<{
readonly languageOptions: LanguageOptions
readonly payload: BasePayload
readonly theme: Config['admin']['theme']
readonly user?: User
readonly user?: TypedUser
}> = (props) => {
const { className, i18n, languageOptions, payload, theme, user } = props

View File

@@ -4,8 +4,8 @@ import {
type PayloadRequest,
type SelectType,
type Sort,
type TypedUser,
type TypeWithVersion,
type User,
type Where,
} from 'payload'
@@ -28,7 +28,7 @@ export const fetchVersion = async <TVersionData extends object = object>({
overrideAccess?: boolean
req: PayloadRequest
select?: SelectType
user?: User
user?: TypedUser
}): Promise<null | TypeWithVersion<TVersionData>> => {
try {
if (collectionSlug) {
@@ -88,7 +88,7 @@ export const fetchVersions = async <TVersionData extends object = object>({
req: PayloadRequest
select?: SelectType
sort?: Sort
user?: User
user?: TypedUser
where?: Where
}): Promise<null | PaginatedDocs<TypeWithVersion<TVersionData>>> => {
const where: Where = { and: [...(whereFromArgs ? [whereFromArgs] : [])] }
@@ -160,7 +160,7 @@ export const fetchLatestVersion = async <TVersionData extends object = object>({
req: PayloadRequest
select?: SelectType
status: 'draft' | 'published'
user?: User
user?: TypedUser
where?: Where
}): Promise<null | TypeWithVersion<TVersionData>> => {
const and: Where[] = [

View File

@@ -4,7 +4,7 @@ import type {
SanitizedCollectionConfig,
SanitizedConfig,
SanitizedGlobalConfig,
User,
TypedUser,
} from 'payload'
export type DefaultVersionsViewProps = {
@@ -18,6 +18,6 @@ export type DefaultVersionsViewProps = {
i18n: I18n
id: number | string
limit: number
user: User
user: TypedUser
versionsData: PaginatedDocs<Document>
}

View File

@@ -1,8 +1,9 @@
import type { I18nClient } from '@payloadcms/translations'
import type { MarkOptional } from 'ts-essentials'
import type { SanitizedFieldPermissions, User } from '../../auth/types.js'
import type { SanitizedFieldPermissions } from '../../auth/types.js'
import type { ClientBlock, ClientField, Field } from '../../fields/config/types.js'
import type { TypedUser } from '../../index.js'
import type { DocumentPreferences } from '../../preferences/types.js'
import type { Operation, Payload, PayloadRequest } from '../../types/index.js'
import type {
@@ -90,7 +91,7 @@ export type ServerComponentProps = {
preferences: DocumentPreferences
req: PayloadRequest
siblingData: Data
user: User
user: TypedUser
value?: unknown
}

View File

@@ -5,9 +5,8 @@ import type {
Collection,
DataFromCollectionSlug,
} from '../../collections/config/types.js'
import type { CollectionSlug } from '../../index.js'
import type { CollectionSlug, TypedUser } from '../../index.js'
import type { PayloadRequest, Where } from '../../types/index.js'
import type { User } from '../types.js'
import { buildAfterOperation } from '../../collections/operations/utils.js'
import {
@@ -32,7 +31,7 @@ import { resetLoginAttempts } from '../strategies/local/resetLoginAttempts.js'
export type Result = {
exp?: number
token?: string
user?: User
user?: TypedUser
}
export type Arguments<TSlug extends CollectionSlug> = {

View File

@@ -1,8 +1,9 @@
import { decodeJwt } from 'jose'
import type { Collection } from '../../collections/config/types.js'
import type { TypedUser } from '../../index.js'
import type { PayloadRequest } from '../../types/index.js'
import type { ClientUser, User } from '../types.js'
import type { ClientUser } from '../types.js'
export type MeOperationResult = {
collection?: string
@@ -42,7 +43,7 @@ export const meOperation = async (args: Arguments): Promise<MeOperationResult> =
overrideAccess: false,
req,
showHiddenFields: false,
})) as User
})) as TypedUser
if (user) {
user.collection = collection.config.slug

View File

@@ -3,8 +3,9 @@ import { URL } from 'url'
import type { Collection } from '../collections/config/types.js'
import type { SanitizedConfig } from '../config/types.js'
import type { InitializedEmailAdapter } from '../email/types.js'
import type { TypedUser } from '../index.js'
import type { PayloadRequest } from '../types/index.js'
import type { User, VerifyConfig } from './types.js'
import type { VerifyConfig } from './types.js'
type Args = {
collection: Collection
@@ -13,7 +14,7 @@ type Args = {
email: InitializedEmailAdapter
req: PayloadRequest
token: string
user: User
user: TypedUser
}
export async function sendVerificationEmail(args: Args): Promise<void> {

View File

@@ -1,8 +1,9 @@
import crypto from 'crypto'
import type { SanitizedCollectionConfig } from '../../collections/config/types.js'
import type { TypedUser } from '../../index.js'
import type { Where } from '../../types/index.js'
import type { AuthStrategyFunction, User } from '../index.js'
import type { AuthStrategyFunction } from '../index.js'
export const APIKeyAuthentication =
(collectionConfig: SanitizedCollectionConfig): AuthStrategyFunction =>
@@ -49,7 +50,7 @@ export const APIKeyAuthentication =
user!._strategy = 'api-key'
return {
user: user as User,
user: user as TypedUser,
}
}
} catch (ignore) {

View File

@@ -1,6 +1,6 @@
import type { DeepRequired } from 'ts-essentials'
import type { CollectionSlug, GlobalSlug, Payload } from '../index.js'
import type { CollectionSlug, GlobalSlug, Payload, TypedUser } from '../index.js'
import type { PayloadRequest, Where } from '../types/index.js'
/**
@@ -122,7 +122,10 @@ type BaseUser = {
username?: string
}
export type User = {
/**
* @deprecated Use `TypedUser` instead. This will be removed in 4.0.
*/
export type UntypedUser = {
[key: string]: any
} & BaseUser
@@ -179,7 +182,7 @@ export type AuthStrategyResult = {
| ({
_strategy?: string
collection?: string
} & User)
} & TypedUser)
| null
}

View File

@@ -15,7 +15,7 @@ import type { AuthArgs } from './auth/operations/auth.js'
import type { Result as ForgotPasswordResult } from './auth/operations/forgotPassword.js'
import type { Result as LoginResult } from './auth/operations/login.js'
import type { Result as ResetPasswordResult } from './auth/operations/resetPassword.js'
import type { AuthStrategy, User } from './auth/types.js'
import type { AuthStrategy, UntypedUser } from './auth/types.js'
import type {
BulkOperationResult,
Collection,
@@ -216,7 +216,7 @@ export interface GeneratedTypes {
}
}
localeUntyped: null | string
userUntyped: User
userUntyped: UntypedUser
}
// Helper type to resolve the correct type using conditional types
@@ -299,6 +299,10 @@ type ResolveLocaleType<T> = 'locale' extends keyof T ? T['locale'] : T['localeUn
type ResolveUserType<T> = 'user' extends keyof T ? T['user'] : T['userUntyped']
export type TypedLocale = ResolveLocaleType<GeneratedTypes>
/**
* @todo rename to `User` in 4.0
*/
export type TypedUser = ResolveUserType<GeneratedTypes>
// @ts-expect-error
@@ -1099,7 +1103,7 @@ export type {
SanitizedFieldPermissions,
SanitizedGlobalPermission,
SanitizedPermissions,
User,
UntypedUser as User,
VerifyConfig,
} from './auth/types.js'
export { generateImportMap } from './bin/generateImportMap/index.js'

View File

@@ -1,5 +1,4 @@
import type { User } from '../auth/types.js'
import type { Payload, RequestContext, TypedLocale } from '../index.js'
import type { Payload, RequestContext, TypedLocale, TypedUser } from '../index.js'
import type { PayloadRequest } from '../types/index.js'
import { getDataLoader } from '../collections/dataloader.js'
@@ -91,7 +90,7 @@ export type CreateLocalReqOptions = {
locale?: string
req?: Partial<PayloadRequest>
urlSuffix?: string
user?: User
user?: TypedUser
}
type CreateLocalReq = (options: CreateLocalReqOptions, payload: Payload) => Promise<PayloadRequest>

View File

@@ -1,5 +1,5 @@
import type { User } from '../../auth/types.js'
import type { Field } from '../../fields/config/types.js'
import type { TypedUser } from '../../index.js'
import type { TaskConfig } from '../../queues/config/types/taskTypes.js'
import type { SchedulePublishTaskInput } from './types.js'
@@ -21,14 +21,14 @@ export const getSchedulePublishTask = ({
const userID = input.user
let user: null | User = null
let user: null | TypedUser = null
if (userID) {
user = (await req.payload.findByID({
id: userID,
collection: adminUserSlug,
depth: 0,
})) as User
})) as TypedUser
user.collection = adminUserSlug
}

View File

@@ -1,5 +1,5 @@
/* eslint-disable perfectionist/sort-objects */
import type { PayloadRequest, Sort, User, Where } from 'payload'
import type { PayloadRequest, Sort, TypedUser, Where } from 'payload'
import { stringify } from 'csv-stringify/sync'
import { APIError } from 'payload'
@@ -38,7 +38,7 @@ export type CreateExportArgs = {
download?: boolean
input: Export
req: PayloadRequest
user?: User
user?: TypedUser
}
export const createExport = async (args: CreateExportArgs) => {

View File

@@ -1,4 +1,4 @@
import type { Config, TaskConfig, User } from 'payload'
import type { Config, TaskConfig, TypedUser } from 'payload'
import type { CreateExportArgs, Export } from './createExport.js'
@@ -29,13 +29,13 @@ export const getCreateCollectionExportTask = (
return {
slug: 'createCollectionExport',
handler: async ({ input, req }: CreateExportArgs) => {
let user: undefined | User
let user: TypedUser | undefined
if (input.userCollection && input.user) {
user = (await req.payload.findByID({
id: input.user,
collection: input.userCollection,
})) as User
})) as TypedUser
}
if (!user) {

View File

@@ -1,4 +1,4 @@
import type { OptionObject, Payload, User } from 'payload'
import type { OptionObject, Payload, TypedUser } from 'payload'
import { cookies as getCookies } from 'next/headers.js'
@@ -10,7 +10,7 @@ type Args = {
payload: Payload
tenantsCollectionSlug: string
useAsTitle: string
user: User
user: TypedUser
}
export const TenantSelectionProvider = async ({

View File

@@ -1,11 +1,11 @@
import type { PaginatedDocs, Payload, User } from 'payload'
import type { PaginatedDocs, Payload, TypedUser } from 'payload'
type Args = {
limit: number
payload: Payload
tenantsCollectionSlug: string
useAsTitle: string
user?: User
user?: TypedUser
}
export const findTenantOptions = async ({
limit,

View File

@@ -1,5 +1,5 @@
import type { AcceptedLanguages } from '@payloadcms/translations'
import type { ArrayField, CollectionSlug, Field, RelationshipField, User } from 'payload'
import type { ArrayField, CollectionSlug, Field, RelationshipField, TypedUser } from 'payload'
export type MultiTenantPluginConfig<ConfigTypes = unknown> = {
/**
@@ -138,7 +138,7 @@ export type MultiTenantPluginConfig<ConfigTypes = unknown> = {
* Useful for super-admin type users
*/
userHasAccessToAllTenants?: (
user: ConfigTypes extends { user: unknown } ? ConfigTypes['user'] : User,
user: ConfigTypes extends { user: unknown } ? ConfigTypes['user'] : TypedUser,
) => boolean
/**
* Opt out of adding access constraints to the tenants collection
@@ -165,4 +165,4 @@ export type UserWithTenantsField = {
tenant: number | string | Tenant
}[]
| null
} & User
} & TypedUser

View File

@@ -1,4 +1,4 @@
import type { Payload, User, ViewTypes } from 'payload'
import type { Payload, TypedUser, ViewTypes } from 'payload'
import { formatAdminURL } from 'payload/shared'
@@ -15,7 +15,7 @@ type Args = {
tenantFieldName: string
tenantsCollectionSlug: string
useAsTitle: string
user?: User
user?: TypedUser
view: ViewTypes
}
export async function getGlobalViewRedirect({

View File

@@ -4,7 +4,7 @@ import type {
AccessResult,
AllOperations,
CollectionConfig,
User,
TypedUser,
Where,
} from 'payload'
@@ -53,7 +53,7 @@ export const withTenantAccess =
args.req.user &&
args.req.user.collection === adminUsersSlug &&
!userHasAccessToAllTenants(
args.req.user as ConfigType extends { user: unknown } ? ConfigType['user'] : User,
args.req.user as ConfigType extends { user: unknown } ? ConfigType['user'] : TypedUser,
)
) {
const tenantConstraint = getTenantAccess({

View File

@@ -5,7 +5,7 @@ import type {
SanitizedConfig,
TextField,
TextFieldSingleValidation,
User,
TypedUser,
} from 'payload'
import type { LinkFields } from '../nodes/types.js'
@@ -120,7 +120,7 @@ export const getBaseFields = (
? ({ relationTo, user }) => {
const hidden = config.collections.find(({ slug }) => slug === relationTo)?.admin
.hidden
if (typeof hidden === 'function' && hidden({ user } as { user: User })) {
if (typeof hidden === 'function' && hidden({ user } as { user: TypedUser })) {
return false
}
return true

View File

@@ -1,4 +1,4 @@
import type { Field, SanitizedConfig, User } from 'payload'
import type { Field, SanitizedConfig, TypedUser } from 'payload'
export const getBaseFields = (config: SanitizedConfig): Field[] => [
{
@@ -47,7 +47,7 @@ export const getBaseFields = (config: SanitizedConfig): Field[] => [
type: 'relationship',
filterOptions: ({ relationTo, user }) => {
const hidden = config.collections.find(({ slug }) => slug === relationTo).admin.hidden
if (typeof hidden === 'function' && hidden({ user } as { user: User })) {
if (typeof hidden === 'function' && hidden({ user } as { user: TypedUser })) {
return false
}
},

View File

@@ -4,7 +4,7 @@ import type {
FormField,
FormState,
Row,
User,
TypedUser,
ValidationFieldError,
} from 'payload'
import type React from 'react'
@@ -123,7 +123,7 @@ export type MODIFY_CONDITION = {
path: string
result: boolean
type: 'MODIFY_CONDITION'
user: User
user: TypedUser
}
export type UPDATE = {

View File

@@ -4,7 +4,7 @@ import type {
PayloadRequest,
SelectMode,
SelectType,
User,
TypedUser,
} from 'payload'
import { iterateFields } from './iterateFields.js'
@@ -18,7 +18,7 @@ type Args = {
select?: SelectType
selectMode?: SelectMode
siblingData: Data
user: User
user: TypedUser
}
export const calculateDefaultValues = async ({

View File

@@ -1,4 +1,12 @@
import type { Data, Field, PayloadRequest, SelectMode, SelectType, TabAsField, User } from 'payload'
import type {
Data,
Field,
PayloadRequest,
SelectMode,
SelectType,
TabAsField,
TypedUser,
} from 'payload'
import { defaultValuePromise } from './promise.js'
@@ -11,7 +19,7 @@ type Args<T> = {
select?: SelectType
selectMode?: SelectMode
siblingData: Data
user: User
user: TypedUser
}
export const iterateFields = async <T>({

View File

@@ -6,7 +6,7 @@ import type {
SelectMode,
SelectType,
TabAsField,
User,
TypedUser,
} from 'payload'
import { getBlockSelect, getDefaultValue, stripUnselectedFields } from 'payload'
@@ -23,7 +23,7 @@ type Args<T> = {
select?: SelectType
selectMode?: SelectMode
siblingData: Data
user: User
user: TypedUser
}
// TODO: Make this works for rich text subfields

View File

@@ -1,5 +1,5 @@
'use client'
import type { ClientUser, SanitizedPermissions, User } from 'payload'
import type { ClientUser, SanitizedPermissions, TypedUser } from 'payload'
import { useModal } from '@faceless-ui/modal'
import { usePathname, useRouter } from 'next/navigation.js'
@@ -23,7 +23,7 @@ export type UserWithToken<T = ClientUser> = {
}
export type AuthContext<T = ClientUser> = {
fetchFullUser: () => Promise<null | User>
fetchFullUser: () => Promise<null | TypedUser>
logOut: () => Promise<boolean>
permissions?: SanitizedPermissions
refreshCookie: (forceRefresh?: boolean) => void

View File

@@ -6,7 +6,7 @@ import type {
Locale,
SanitizedPermissions,
ServerFunctionClient,
User,
TypedUser,
} from 'payload'
import { DndContext, pointerWithin } from '@dnd-kit/core'
@@ -52,7 +52,7 @@ type Props = {
readonly switchLanguageServerAction?: (lang: string) => Promise<void>
readonly theme: Theme
readonly translations: I18nClient['translations']
readonly user: null | User
readonly user: null | TypedUser
}
export const RootProvider: React.FC<Props> = ({

View File

@@ -128,6 +128,13 @@ export interface User {
hash?: string | null;
loginAttempts?: number | null;
lockUntil?: string | null;
sessions?:
| {
id: string;
createdAt?: string | null;
expiresAt: string;
}[]
| null;
password?: string | null;
}
/**
@@ -220,6 +227,13 @@ export interface UsersSelect<T extends boolean = true> {
hash?: T;
loginAttempts?: T;
lockUntil?: T;
sessions?:
| T
| {
id?: T;
createdAt?: T;
expiresAt?: T;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema

View File

@@ -36,6 +36,8 @@
"dev:generate-importmap": "pnpm dev:payload generate:importmap",
"dev:generate-types": "pnpm dev:payload generate:types",
"dev:payload": "cross-env PAYLOAD_CONFIG_PATH=./dev/payload.config.ts payload",
"generate:types": "pnpm dev:generate-types",
"generate:importmap": "pnpm dev:generate-importmap",
"lint": "eslint",
"lint:fix": "eslint ./src --fix",
"prepublishOnly": "pnpm clean && pnpm build",

View File

@@ -383,6 +383,13 @@ export interface User {
hash?: string | null;
loginAttempts?: number | null;
lockUntil?: string | null;
sessions?:
| {
id: string;
createdAt?: string | null;
expiresAt: string;
}[]
| null;
password?: string | null;
}
/**
@@ -1276,6 +1283,13 @@ export interface UsersSelect<T extends boolean = true> {
hash?: T;
loginAttempts?: T;
lockUntil?: T;
sessions?:
| T
| {
id?: T;
createdAt?: T;
expiresAt?: T;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema

View File

@@ -6,7 +6,6 @@
"type": "module",
"scripts": {
"build": "cross-env NODE_OPTIONS=--no-deprecation next build",
"ci": "payload migrate && pnpm build",
"dev": "cross-env NODE_OPTIONS=--no-deprecation next dev",
"devsafe": "rm -rf .next && cross-env NODE_OPTIONS=--no-deprecation next dev",
"generate:importmap": "cross-env NODE_OPTIONS=--no-deprecation payload generate:importmap",
@@ -16,21 +15,22 @@
"start": "cross-env NODE_OPTIONS=--no-deprecation next start",
"test": "pnpm run test:int && pnpm run test:e2e",
"test:e2e": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" pnpm exec playwright test",
"test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts"
"test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts",
"ci": "payload migrate && pnpm build"
},
"dependencies": {
"@payloadcms/db-postgres": "3.43.0",
"@payloadcms/next": "3.43.0",
"@payloadcms/payload-cloud": "3.43.0",
"@payloadcms/richtext-lexical": "3.43.0",
"@payloadcms/ui": "3.43.0",
"@payloadcms/next": "3.44.0",
"@payloadcms/payload-cloud": "3.44.0",
"@payloadcms/richtext-lexical": "3.44.0",
"@payloadcms/ui": "3.44.0",
"cross-env": "^7.0.3",
"graphql": "^16.8.1",
"next": "15.3.0",
"payload": "3.43.0",
"payload": "3.44.0",
"react": "19.1.0",
"react-dom": "19.1.0",
"sharp": "0.32.6"
"sharp": "0.32.6",
"@payloadcms/db-postgres": "3.44.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",

View File

@@ -1,9 +1,93 @@
{
"id": "fd232901-8d4d-4ce0-93b1-988f26975158",
"id": "77ca1be4-16d8-4f65-bad8-0b86d2692050",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.users_sessions": {
"name": "users_sessions",
"schema": "",
"columns": {
"_order": {
"name": "_order",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"_parent_id": {
"name": "_parent_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "varchar",
"primaryKey": true,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp(3) with time zone",
"primaryKey": false,
"notNull": false
},
"expires_at": {
"name": "expires_at",
"type": "timestamp(3) with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"users_sessions_order_idx": {
"name": "users_sessions_order_idx",
"columns": [
{
"expression": "_order",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"users_sessions_parent_id_idx": {
"name": "users_sessions_parent_id_idx",
"columns": [
{
"expression": "_parent_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"users_sessions_parent_id_fk": {
"name": "users_sessions_parent_id_fk",
"tableFrom": "users_sessions",
"tableTo": "users",
"columnsFrom": ["_parent_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.users": {
"name": "users",
"schema": "",

View File

@@ -2,6 +2,14 @@ import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
CREATE TABLE "users_sessions" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"created_at" timestamp(3) with time zone,
"expires_at" timestamp(3) with time zone NOT NULL
);
CREATE TABLE "users" (
"id" serial PRIMARY KEY NOT NULL,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
@@ -71,11 +79,14 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
ALTER TABLE "users_sessions" ADD CONSTRAINT "users_sessions_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_locked_documents"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_preferences"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "users_sessions_order_idx" ON "users_sessions" USING btree ("_order");
CREATE INDEX "users_sessions_parent_id_idx" ON "users_sessions" USING btree ("_parent_id");
CREATE INDEX "users_updated_at_idx" ON "users" USING btree ("updated_at");
CREATE INDEX "users_created_at_idx" ON "users" USING btree ("created_at");
CREATE UNIQUE INDEX "users_email_idx" ON "users" USING btree ("email");
@@ -103,6 +114,7 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
DROP TABLE "users_sessions" CASCADE;
DROP TABLE "users" CASCADE;
DROP TABLE "media" CASCADE;
DROP TABLE "payload_locked_documents" CASCADE;

View File

@@ -1,9 +1,9 @@
import * as migration_20250616_201724_initial from './20250616_201724_initial'
import * as migration_20250629_202651_initial from './20250629_202651_initial'
export const migrations = [
{
up: migration_20250616_201724_initial.up,
down: migration_20250616_201724_initial.down,
name: '20250616_201724_initial',
up: migration_20250629_202651_initial.up,
down: migration_20250629_202651_initial.down,
name: '20250629_202651_initial',
},
]

View File

@@ -128,6 +128,13 @@ export interface User {
hash?: string | null;
loginAttempts?: number | null;
lockUntil?: string | null;
sessions?:
| {
id: string;
createdAt?: string | null;
expiresAt: string;
}[]
| null;
password?: string | null;
}
/**
@@ -220,6 +227,13 @@ export interface UsersSelect<T extends boolean = true> {
hash?: T;
loginAttempts?: T;
lockUntil?: T;
sessions?:
| T
| {
id?: T;
createdAt?: T;
expiresAt?: T;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema

View File

@@ -18,18 +18,18 @@
"test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts"
},
"dependencies": {
"@payloadcms/db-mongodb": "3.43.0",
"@payloadcms/next": "3.43.0",
"@payloadcms/payload-cloud": "3.43.0",
"@payloadcms/richtext-lexical": "3.43.0",
"@payloadcms/storage-vercel-blob": "3.43.0",
"@payloadcms/ui": "3.43.0",
"@payloadcms/db-mongodb": "3.44.0",
"@payloadcms/next": "3.44.0",
"@payloadcms/payload-cloud": "3.44.0",
"@payloadcms/richtext-lexical": "3.44.0",
"@payloadcms/ui": "3.44.0",
"cross-env": "^7.0.3",
"graphql": "^16.8.1",
"next": "15.3.0",
"payload": "3.43.0",
"payload": "3.44.0",
"react": "19.1.0",
"react-dom": "19.1.0"
"react-dom": "19.1.0",
"@payloadcms/storage-vercel-blob": "3.44.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
@@ -49,7 +49,6 @@
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.3"
},
"packageManager": "pnpm@10.12.3",
"engines": {
"node": "^18.20.2 || >=20.9.0"
},
@@ -57,5 +56,6 @@
"onlyBuiltDependencies": [
"sharp"
]
}
},
"packageManager": "pnpm@10.12.4"
}

View File

@@ -6,24 +6,94 @@
* and re-run `payload generate:types` to regenerate this file.
*/
/**
* Supported timezones in IANA format.
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "supportedTimezones".
*/
export type SupportedTimezones =
| 'Pacific/Midway'
| 'Pacific/Niue'
| 'Pacific/Honolulu'
| 'Pacific/Rarotonga'
| 'America/Anchorage'
| 'Pacific/Gambier'
| 'America/Los_Angeles'
| 'America/Tijuana'
| 'America/Denver'
| 'America/Phoenix'
| 'America/Chicago'
| 'America/Guatemala'
| 'America/New_York'
| 'America/Bogota'
| 'America/Caracas'
| 'America/Santiago'
| 'America/Buenos_Aires'
| 'America/Sao_Paulo'
| 'Atlantic/South_Georgia'
| 'Atlantic/Azores'
| 'Atlantic/Cape_Verde'
| 'Europe/London'
| 'Europe/Berlin'
| 'Africa/Lagos'
| 'Europe/Athens'
| 'Africa/Cairo'
| 'Europe/Moscow'
| 'Asia/Riyadh'
| 'Asia/Dubai'
| 'Asia/Baku'
| 'Asia/Karachi'
| 'Asia/Tashkent'
| 'Asia/Calcutta'
| 'Asia/Dhaka'
| 'Asia/Almaty'
| 'Asia/Jakarta'
| 'Asia/Bangkok'
| 'Asia/Shanghai'
| 'Asia/Singapore'
| 'Asia/Tokyo'
| 'Asia/Seoul'
| 'Australia/Brisbane'
| 'Australia/Sydney'
| 'Pacific/Guam'
| 'Pacific/Noumea'
| 'Pacific/Auckland'
| 'Pacific/Fiji';
export interface Config {
auth: {
users: UserAuthOperations;
};
blocks: {};
collections: {
users: User;
media: Media;
'payload-locked-documents': PayloadLockedDocument;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
collectionsJoins: {};
collectionsSelect: {
users: UsersSelect<false> | UsersSelect<true>;
media: MediaSelect<false> | MediaSelect<true>;
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
};
db: {
defaultIDType: string;
};
globals: {};
globalsSelect: {};
locale: null;
user: User & {
collection: 'users';
};
jobs: {
tasks: unknown;
workflows: unknown;
};
}
export interface UserAuthOperations {
forgotPassword: {
@@ -58,6 +128,13 @@ export interface User {
hash?: string | null;
loginAttempts?: number | null;
lockUntil?: string | null;
sessions?:
| {
id: string;
createdAt?: string | null;
expiresAt: string;
}[]
| null;
password?: string | null;
}
/**
@@ -79,6 +156,29 @@ export interface Media {
focalX?: number | null;
focalY?: number | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents".
*/
export interface PayloadLockedDocument {
id: string;
document?:
| ({
relationTo: 'users';
value: string | User;
} | null)
| ({
relationTo: 'media';
value: string | Media;
} | null);
globalSlug?: string | null;
user: {
relationTo: 'users';
value: string | User;
};
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences".
@@ -113,6 +213,78 @@ export interface PayloadMigration {
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users_select".
*/
export interface UsersSelect<T extends boolean = true> {
updatedAt?: T;
createdAt?: T;
email?: T;
resetPasswordToken?: T;
resetPasswordExpiration?: T;
salt?: T;
hash?: T;
loginAttempts?: T;
lockUntil?: T;
sessions?:
| T
| {
id?: T;
createdAt?: T;
expiresAt?: T;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media_select".
*/
export interface MediaSelect<T extends boolean = true> {
alt?: T;
updatedAt?: T;
createdAt?: T;
url?: T;
thumbnailURL?: T;
filename?: T;
mimeType?: T;
filesize?: T;
width?: T;
height?: T;
focalX?: T;
focalY?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-locked-documents_select".
*/
export interface PayloadLockedDocumentsSelect<T extends boolean = true> {
document?: T;
globalSlug?: T;
user?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-preferences_select".
*/
export interface PayloadPreferencesSelect<T extends boolean = true> {
user?: T;
key?: T;
value?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "payload-migrations_select".
*/
export interface PayloadMigrationsSelect<T extends boolean = true> {
name?: T;
batch?: T;
updatedAt?: T;
createdAt?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "auth".

View File

@@ -6,7 +6,6 @@
"type": "module",
"scripts": {
"build": "cross-env NODE_OPTIONS=--no-deprecation next build",
"ci": "payload migrate && pnpm build",
"dev": "cross-env NODE_OPTIONS=--no-deprecation next dev",
"devsafe": "rm -rf .next && cross-env NODE_OPTIONS=--no-deprecation next dev",
"generate:importmap": "cross-env NODE_OPTIONS=--no-deprecation payload generate:importmap",
@@ -16,21 +15,22 @@
"start": "cross-env NODE_OPTIONS=--no-deprecation next start",
"test": "pnpm run test:int && pnpm run test:e2e",
"test:e2e": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" pnpm exec playwright test",
"test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts"
"test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts",
"ci": "payload migrate && pnpm build"
},
"dependencies": {
"@payloadcms/db-vercel-postgres": "3.43.0",
"@payloadcms/next": "3.43.0",
"@payloadcms/payload-cloud": "3.43.0",
"@payloadcms/richtext-lexical": "3.43.0",
"@payloadcms/storage-vercel-blob": "3.43.0",
"@payloadcms/ui": "3.43.0",
"@payloadcms/next": "3.44.0",
"@payloadcms/payload-cloud": "3.44.0",
"@payloadcms/richtext-lexical": "3.44.0",
"@payloadcms/ui": "3.44.0",
"cross-env": "^7.0.3",
"graphql": "^16.8.1",
"next": "15.3.0",
"payload": "3.43.0",
"payload": "3.44.0",
"react": "19.1.0",
"react-dom": "19.1.0"
"react-dom": "19.1.0",
"@payloadcms/db-vercel-postgres": "3.44.0",
"@payloadcms/storage-vercel-blob": "3.44.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
@@ -50,7 +50,6 @@
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.3"
},
"packageManager": "pnpm@10.12.3",
"engines": {
"node": "^18.20.2 || >=20.9.0"
},
@@ -58,5 +57,6 @@
"onlyBuiltDependencies": [
"sharp"
]
}
},
"packageManager": "pnpm@10.12.4"
}

View File

@@ -1,9 +1,93 @@
{
"id": "64c3b19c-9d51-4e55-9c9c-333d9b73bc28",
"id": "f6e3ff1c-ee75-4b76-9e36-3e30ac7f87a1",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.users_sessions": {
"name": "users_sessions",
"schema": "",
"columns": {
"_order": {
"name": "_order",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"_parent_id": {
"name": "_parent_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "varchar",
"primaryKey": true,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp(3) with time zone",
"primaryKey": false,
"notNull": false
},
"expires_at": {
"name": "expires_at",
"type": "timestamp(3) with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"users_sessions_order_idx": {
"name": "users_sessions_order_idx",
"columns": [
{
"expression": "_order",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"users_sessions_parent_id_idx": {
"name": "users_sessions_parent_id_idx",
"columns": [
{
"expression": "_parent_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"users_sessions_parent_id_fk": {
"name": "users_sessions_parent_id_fk",
"tableFrom": "users_sessions",
"tableTo": "users",
"columnsFrom": ["_parent_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.users": {
"name": "users",
"schema": "",

View File

@@ -2,6 +2,14 @@ import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-vercel-postg
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
CREATE TABLE "users_sessions" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"created_at" timestamp(3) with time zone,
"expires_at" timestamp(3) with time zone NOT NULL
);
CREATE TABLE "users" (
"id" serial PRIMARY KEY NOT NULL,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
@@ -71,11 +79,14 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
ALTER TABLE "users_sessions" ADD CONSTRAINT "users_sessions_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_locked_documents"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_preferences"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
CREATE INDEX "users_sessions_order_idx" ON "users_sessions" USING btree ("_order");
CREATE INDEX "users_sessions_parent_id_idx" ON "users_sessions" USING btree ("_parent_id");
CREATE INDEX "users_updated_at_idx" ON "users" USING btree ("updated_at");
CREATE INDEX "users_created_at_idx" ON "users" USING btree ("created_at");
CREATE UNIQUE INDEX "users_email_idx" ON "users" USING btree ("email");
@@ -103,6 +114,7 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
DROP TABLE "users_sessions" CASCADE;
DROP TABLE "users" CASCADE;
DROP TABLE "media" CASCADE;
DROP TABLE "payload_locked_documents" CASCADE;

View File

@@ -1,9 +1,9 @@
import * as migration_20250624_171210_initial from './20250624_171210_initial'
import * as migration_20250629_202637_initial from './20250629_202637_initial'
export const migrations = [
{
up: migration_20250624_171210_initial.up,
down: migration_20250624_171210_initial.down,
name: '20250624_171210_initial',
up: migration_20250629_202637_initial.up,
down: migration_20250629_202637_initial.down,
name: '20250629_202637_initial',
},
]

View File

@@ -128,6 +128,13 @@ export interface User {
hash?: string | null;
loginAttempts?: number | null;
lockUntil?: string | null;
sessions?:
| {
id: string;
createdAt?: string | null;
expiresAt: string;
}[]
| null;
password?: string | null;
}
/**
@@ -220,6 +227,13 @@ export interface UsersSelect<T extends boolean = true> {
hash?: T;
loginAttempts?: T;
lockUntil?: T;
sessions?:
| T
| {
id?: T;
createdAt?: T;
expiresAt?: T;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema

View File

@@ -7,7 +7,6 @@
"scripts": {
"build": "cross-env NODE_OPTIONS=--no-deprecation next build",
"postbuild": "next-sitemap --config next-sitemap.config.cjs",
"ci": "payload migrate && pnpm build",
"dev": "cross-env NODE_OPTIONS=--no-deprecation next dev",
"dev:prod": "cross-env NODE_OPTIONS=--no-deprecation rm -rf .next && pnpm build && pnpm start",
"generate:importmap": "cross-env NODE_OPTIONS=--no-deprecation payload generate:importmap",
@@ -20,22 +19,21 @@
"start": "cross-env NODE_OPTIONS=--no-deprecation next start",
"test": "pnpm run test:int && pnpm run test:e2e",
"test:e2e": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" pnpm exec playwright test --config=playwright.config.ts",
"test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts"
"test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts",
"ci": "payload migrate && pnpm build"
},
"dependencies": {
"@payloadcms/admin-bar": "3.43.0",
"@payloadcms/db-vercel-postgres": "3.43.0",
"@payloadcms/live-preview-react": "3.43.0",
"@payloadcms/next": "3.43.0",
"@payloadcms/payload-cloud": "3.43.0",
"@payloadcms/plugin-form-builder": "3.43.0",
"@payloadcms/plugin-nested-docs": "3.43.0",
"@payloadcms/plugin-redirects": "3.43.0",
"@payloadcms/plugin-search": "3.43.0",
"@payloadcms/plugin-seo": "3.43.0",
"@payloadcms/richtext-lexical": "3.43.0",
"@payloadcms/storage-vercel-blob": "3.43.0",
"@payloadcms/ui": "3.43.0",
"@payloadcms/admin-bar": "3.44.0",
"@payloadcms/live-preview-react": "3.44.0",
"@payloadcms/next": "3.44.0",
"@payloadcms/payload-cloud": "3.44.0",
"@payloadcms/plugin-form-builder": "3.44.0",
"@payloadcms/plugin-nested-docs": "3.44.0",
"@payloadcms/plugin-redirects": "3.44.0",
"@payloadcms/plugin-search": "3.44.0",
"@payloadcms/plugin-seo": "3.44.0",
"@payloadcms/richtext-lexical": "3.44.0",
"@payloadcms/ui": "3.44.0",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-select": "^2.0.0",
@@ -49,14 +47,16 @@
"lucide-react": "^0.378.0",
"next": "15.3.3",
"next-sitemap": "^4.2.3",
"payload": "3.43.0",
"payload": "3.44.0",
"prism-react-renderer": "^2.3.1",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-hook-form": "7.45.4",
"sharp": "0.32.6",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"@payloadcms/db-vercel-postgres": "3.44.0",
"@payloadcms/storage-vercel-blob": "3.44.0"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
@@ -82,7 +82,6 @@
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.3"
},
"packageManager": "pnpm@10.12.3",
"engines": {
"node": "^18.20.2 || >=20.9.0"
},
@@ -90,5 +89,6 @@
"onlyBuiltDependencies": [
"sharp"
]
}
},
"packageManager": "pnpm@10.12.4"
}

View File

@@ -1,5 +1,5 @@
{
"id": "6a44166d-9436-4c05-8f1e-a79a4d523d1c",
"id": "a31dfac2-cdc9-41d5-97e2-2aa6f567d3f8",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
@@ -4639,6 +4639,90 @@
"checkConstraints": {},
"isRLSEnabled": false
},
"public.users_sessions": {
"name": "users_sessions",
"schema": "",
"columns": {
"_order": {
"name": "_order",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"_parent_id": {
"name": "_parent_id",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "varchar",
"primaryKey": true,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp(3) with time zone",
"primaryKey": false,
"notNull": false
},
"expires_at": {
"name": "expires_at",
"type": "timestamp(3) with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"users_sessions_order_idx": {
"name": "users_sessions_order_idx",
"columns": [
{
"expression": "_order",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"users_sessions_parent_id_idx": {
"name": "users_sessions_parent_id_idx",
"columns": [
{
"expression": "_parent_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"users_sessions_parent_id_fk": {
"name": "users_sessions_parent_id_fk",
"tableFrom": "users_sessions",
"tableTo": "users",
"columnsFrom": ["_parent_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.users": {
"name": "users",
"schema": "",

View File

@@ -420,6 +420,14 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);
CREATE TABLE "users_sessions" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"created_at" timestamp(3) with time zone,
"expires_at" timestamp(3) with time zone NOT NULL
);
CREATE TABLE "users" (
"id" serial PRIMARY KEY NOT NULL,
"name" varchar,
@@ -817,6 +825,7 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
ALTER TABLE "categories_breadcrumbs" ADD CONSTRAINT "categories_breadcrumbs_doc_id_categories_id_fk" FOREIGN KEY ("doc_id") REFERENCES "public"."categories"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "categories_breadcrumbs" ADD CONSTRAINT "categories_breadcrumbs_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."categories"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "categories" ADD CONSTRAINT "categories_parent_id_categories_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."categories"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "users_sessions" ADD CONSTRAINT "users_sessions_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "redirects_rels" ADD CONSTRAINT "redirects_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."redirects"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "redirects_rels" ADD CONSTRAINT "redirects_rels_pages_fk" FOREIGN KEY ("pages_id") REFERENCES "public"."pages"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "redirects_rels" ADD CONSTRAINT "redirects_rels_posts_fk" FOREIGN KEY ("posts_id") REFERENCES "public"."posts"("id") ON DELETE cascade ON UPDATE no action;
@@ -984,6 +993,8 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
CREATE INDEX "categories_parent_idx" ON "categories" USING btree ("parent_id");
CREATE INDEX "categories_updated_at_idx" ON "categories" USING btree ("updated_at");
CREATE INDEX "categories_created_at_idx" ON "categories" USING btree ("created_at");
CREATE INDEX "users_sessions_order_idx" ON "users_sessions" USING btree ("_order");
CREATE INDEX "users_sessions_parent_id_idx" ON "users_sessions" USING btree ("_parent_id");
CREATE INDEX "users_updated_at_idx" ON "users" USING btree ("updated_at");
CREATE INDEX "users_created_at_idx" ON "users" USING btree ("created_at");
CREATE UNIQUE INDEX "users_email_idx" ON "users" USING btree ("email");
@@ -1126,6 +1137,7 @@ export async function down({ db, payload, req }: MigrateDownArgs): Promise<void>
DROP TABLE "media" CASCADE;
DROP TABLE "categories_breadcrumbs" CASCADE;
DROP TABLE "categories" CASCADE;
DROP TABLE "users_sessions" CASCADE;
DROP TABLE "users" CASCADE;
DROP TABLE "redirects" CASCADE;
DROP TABLE "redirects_rels" CASCADE;

View File

@@ -1,9 +1,9 @@
import * as migration_20250616_201710_initial from './20250616_201710_initial'
import * as migration_20250629_202644_initial from './20250629_202644_initial'
export const migrations = [
{
up: migration_20250616_201710_initial.up,
down: migration_20250616_201710_initial.down,
name: '20250616_201710_initial',
up: migration_20250629_202644_initial.up,
down: migration_20250629_202644_initial.down,
name: '20250629_202644_initial',
},
]

View File

@@ -383,6 +383,13 @@ export interface User {
hash?: string | null;
loginAttempts?: number | null;
lockUntil?: string | null;
sessions?:
| {
id: string;
createdAt?: string | null;
expiresAt: string;
}[]
| null;
password?: string | null;
}
/**
@@ -1276,6 +1283,13 @@ export interface UsersSelect<T extends boolean = true> {
hash?: T;
loginAttempts?: T;
lockUntil?: T;
sessions?:
| T
| {
id?: T;
createdAt?: T;
expiresAt?: T;
};
}
/**
* This interface was referenced by `Config`'s JSON-Schema

View File

@@ -1,6 +1,6 @@
import { TEMPLATES_DIR } from '@tools/constants'
import chalk from 'chalk'
import { exec as execOrig, execSync } from 'child_process'
import { execSync } from 'child_process'
import fs from 'fs/promises'
import path from 'path'
@@ -46,6 +46,8 @@ async function main() {
const initialPackageJson = await fs.readFile(packageJsonPath, 'utf-8')
const initialPackageJsonObj = JSON.parse(initialPackageJson)
// Update the package.json dependencies to use any specific version instead of `workspace:*`, so that
// the next pnpm add command can install the local packages correctly.
updatePackageJSONDependencies({ latestVersion: '3.42.0', packageJson: initialPackageJsonObj })
await fs.writeFile(packageJsonPath, JSON.stringify(initialPackageJsonObj, null, 2))
@@ -85,7 +87,14 @@ DATABASE_URI=${databaseConnection}
POSTGRES_URL=${databaseConnection}
BLOB_READ_WRITE_TOKEN=vercel_blob_rw_TEST_asdf`,
)
execSync('pnpm run build', execOpts)
// Important: run generate:types and generate:importmap first
if (templateName !== 'plugin') {
// TODO: fix in a separate PR - these commands currently fail in the plugin template
execSync('pnpm --ignore-workspace run generate:types', execOpts)
execSync('pnpm --ignore-workspace run generate:importmap', execOpts)
}
execSync('pnpm --ignore-workspace run build', execOpts)
header(`\n🎉 Done!`)
}

View File

@@ -327,6 +327,12 @@ async function main() {
cwd: destDir,
})
// Generate types
log('Generating types')
execSyncSafe(`pnpm ${workspace ? '' : '--ignore-workspace '}generate:types`, {
cwd: destDir,
})
if (shouldBuild) {
log('Building...')
execSyncSafe(`pnpm ${workspace ? '' : '--ignore-workspace '}build`, { cwd: destDir })